diff --git a/assignment-client/src/AgentScriptingInterface.h b/assignment-client/src/AgentScriptingInterface.h
index 9fa7688778..b1a8aaff96 100644
--- a/assignment-client/src/AgentScriptingInterface.h
+++ b/assignment-client/src/AgentScriptingInterface.h
@@ -18,16 +18,25 @@
#include "Agent.h"
/**jsdoc
+ * The Agent
API enables an assignment client to emulate an avatar. Setting isAvatar = true
connects
+ * the assignment client to the avatar and audio mixers, and enables the {@link Avatar} API to be used.
+ *
* @namespace Agent
*
* @hifi-assignment-client
*
- * @property {boolean} isAvatar
- * @property {boolean} isPlayingAvatarSound Read-only.
- * @property {boolean} isListeningToAudioStream
- * @property {boolean} isNoiseGateEnabled
- * @property {number} lastReceivedAudioLoudness Read-only.
- * @property {Uuid} sessionUUID Read-only.
+ * @property {boolean} isAvatar - true
if the assignment client script is emulating an avatar, otherwise
+ * false
.
+ * @property {boolean} isPlayingAvatarSound - true
if the script has a sound to play, otherwise false
.
+ * Sounds are played when isAvatar
is true
, from the position and with the orientation of the
+ * scripted avatar's head. Read-only.
+ * @property {boolean} isListeningToAudioStream - true
if the agent is "listening" to the audio stream from the
+ * domain, otherwise false
.
+ * @property {boolean} isNoiseGateEnabled - true
if the noise gate is enabled, otherwise false
. When
+ * enabled, the input audio stream is blocked (fully attenuated) if it falls below an adaptive threshold.
+ * @property {number} lastReceivedAudioLoudness - The current loudness of the audio input. Nominal range [0.0
(no
+ * sound) – 1.0
(the onset of clipping)]. Read-only.
+ * @property {Uuid} sessionUUID - The unique ID associated with the agent's current session in the domain. Read-only.
*/
class AgentScriptingInterface : public QObject {
Q_OBJECT
@@ -54,20 +63,43 @@ public:
public slots:
/**jsdoc
+ * Sets whether the script should emulate an avatar.
* @function Agent.setIsAvatar
- * @param {boolean} isAvatar
+ * @param {boolean} isAvatar - true
if the script emulates an avatar, otherwise false
.
+ * @example
true
if the script is emulating an avatar, otherwise false
.
+ * @example isAvatar == true
.
* @function Agent.playAvatarSound
- * @param {object} avatarSound
+ * @param {SoundObject} avatarSound - The sound played.
+ * @example Avatar
API is used to manipulate scriptable avatars on the domain. This API is a subset of the
- * {@link MyAvatar} API.
+ * {@link MyAvatar} API. To enable this API, set {@link Agent|Agent.isAvatar} to true
.
+ *
+ * For Interface, client entity, and avatar scripts, see {@link MyAvatar}.
* - *Note: In the examples, use "Avatar
" instead of "MyAvatar
".
0.005
and
+ * 1000.0
. When the scale value is fetched, it may temporarily be further limited by the domain's settings.
+ * @property {number} density - The density of the avatar in kg/m3. The density is used to work out its mass in
+ * the application of physics. Read-only.
+ * @property {Vec3} handPosition - A user-defined hand position, in world coordinates. The position moves with the avatar
+ * but is otherwise not used or changed by Interface.
+ * @property {number} bodyYaw - The left or right rotation about an axis running from the head to the feet of the avatar.
* Yaw is sometimes called "heading".
* @property {number} bodyPitch - The rotation about an axis running from shoulder to shoulder of the avatar. Pitch is
* sometimes called "elevation".
* @property {number} bodyRoll - The rotation about an axis running from the chest to the back of the avatar. Roll is
* sometimes called "bank".
- * @property {Quat} orientation
+ * @property {Quat} orientation - The orientation of the avatar.
* @property {Quat} headOrientation - The orientation of the avatar's head.
* @property {number} headPitch - The rotation about an axis running from ear to ear of the avatar's head. Pitch is
* sometimes called "elevation".
@@ -46,79 +50,36 @@
* head. Yaw is sometimes called "heading".
* @property {number} headRoll - The rotation about an axis running from the nose to the back of the avatar's head. Roll is
* sometimes called "bank".
- * @property {Vec3} velocity
- * @property {Vec3} angularVelocity
- * @property {number} audioLoudness
- * @property {number} audioAverageLoudness
- * @property {string} displayName
- * @property {string} sessionDisplayName - Sanitized, defaulted version displayName that is defined by the AvatarMixer
- * rather than by Interface clients. The result is unique among all avatars present at the time.
- * @property {boolean} lookAtSnappingEnabled
- * @property {string} skeletonModelURL
- * @property {AttachmentData[]} attachmentData
+ * @property {Vec3} velocity - The current velocity of the avatar.
+ * @property {Vec3} angularVelocity - The current angular velocity of the avatar.
+ * @property {number} audioLoudness - The instantaneous loudness of the audio input that the avatar is injecting into the
+ * domain.
+ * @property {number} audioAverageLoudness - The rolling average loudness of the audio input that the avatar is injecting
+ * into the domain.
+ * @property {string} displayName - The avatar's display name.
+ * @property {string} sessionDisplayName - displayName's
sanitized and default version defined by the avatar mixer
+ * rather than Interface clients. The result is unique among all avatars present in the domain at the time.
+ * @property {boolean} lookAtSnappingEnabled=true - true
if the avatar's eyes snap to look at another avatar's
+ * eyes when the other avatar is in the line of sight and also has lookAtSnappingEnabled == true
.
+ * @property {string} skeletonModelURL - The avatar's FST file.
+ * @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.true
if the animation should loop, false
if it shouldn't.
+ * @param {boolean} [hold=false] - Not used.
+ * @param {number} [firstFrame=0] - The frame at which the animation starts.
+ * @param {number} [lastFrame=3.403e+38] - The frame at which the animation stops.
+ * @param {string[]} [maskedJoints=[]] - The names of joints that should not be animated.
*/
/// Allows scripts to run animations.
Q_INVOKABLE void startAnimation(const QString& url, float fps = 30.0f, float priority = 1.0f, bool loop = false,
@@ -148,39 +111,37 @@ public:
const QStringList& maskedJoints = QStringList());
/**jsdoc
+ * Stops playing the current animation.
* @function Avatar.stopAnimation
*/
Q_INVOKABLE void stopAnimation();
/**jsdoc
+ * Gets the details of the current avatar animation that is being or was recently played.
* @function Avatar.getAnimationDetails
- * @returns {Avatar.AnimationDetails}
+ * @returns {Avatar.AnimationDetails} The current or recent avatar animation.
+ * @example Warning: Potentially an expensive call. Do not use if possible.
* @function Avatar.getAvatarEntityData - * @returns {object} + * @returns {AvatarEntityMap} Details of the avatar entities. + * @exampleWarning: Potentially an expensive call. Do not use if possible.
+ * @function Avatar.setAvatarEntityData + * @param {AvatarEntityMap} avatarEntityData - Details of the avatar entities. + */ Q_INVOKABLE void setAvatarEntityData(const AvatarEntityMap& avatarEntityData) override; /**jsdoc - * @function MyAvatar.updateAvatarEntity - * @param {Uuid} entityID - * @param {string} entityData + * @comment Uses the base class's JSDoc. */ Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) override; public slots: + /**jsdoc + * @function Avatar.update + * @param {number} deltaTime - Delta time. + * @deprecated This function is deprecated and will be removed. + */ void update(float deltatime); /**jsdoc - * @function MyAvatar.setJointMappingsFromNetworkReply - */ + * @function Avatar.setJointMappingsFromNetworkReply + * @deprecated This function is deprecated and will be removed. + */ void setJointMappingsFromNetworkReply(); private: diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index da306f911b..195dd78a0e 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -11,7 +11,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 @@ -31,6 +31,8 @@ Rectangle { property string title: "Audio Settings" property int switchHeight: 16 property int switchWidth: 40 + readonly property real verticalScrollWidth: 10 + readonly property real verticalScrollShaft: 8 signal sendToScript(var message); color: hifi.colors.baseGray; @@ -42,7 +44,7 @@ Rectangle { property bool isVR: AudioScriptingInterface.context === "VR" - property real rightMostInputLevelPos: 450 + property real rightMostInputLevelPos: 440 //placeholder for control sizes and paddings //recalculates dynamically in case of UI size is changed QtObject { @@ -60,8 +62,8 @@ Rectangle { id: bar spacing: 0 width: parent.width - height: 42 - currentIndex: isVR ? 1 : 0 + height: 28; + currentIndex: isVR ? 1 : 0; AudioControls.AudioTabButton { height: parent.height @@ -85,32 +87,92 @@ Rectangle { } function updateMyAvatarGainFromQML(sliderValue, isReleased) { - if (Users.getAvatarGain(myAvatarUuid) != sliderValue) { - Users.setAvatarGain(myAvatarUuid, sliderValue); + if (AudioScriptingInterface.getAvatarGain() != sliderValue) { + AudioScriptingInterface.setAvatarGain(sliderValue); + } + } + function updateInjectorGainFromQML(sliderValue, isReleased) { + if (AudioScriptingInterface.getInjectorGain() != sliderValue) { + AudioScriptingInterface.setInjectorGain(sliderValue); // server side + AudioScriptingInterface.setLocalInjectorGain(sliderValue); // client side + } + } + function updateSystemInjectorGainFromQML(sliderValue, isReleased) { + if (AudioScriptingInterface.getSystemInjectorGain() != sliderValue) { + AudioScriptingInterface.setSystemInjectorGain(sliderValue); } } Component.onCompleted: enablePeakValues(); - Column { - id: column - spacing: 12; - anchors.top: bar.bottom - anchors.bottom: parent.bottom - anchors.bottomMargin: 5 + Flickable { + id: flickView; + anchors.top: bar.bottom; + anchors.left: parent.left; + anchors.bottom: parent.bottom; width: parent.width; + contentWidth: parent.width; + contentHeight: contentItem.childrenRect.height; + boundsBehavior: Flickable.DragOverBounds; + flickableDirection: Flickable.VerticalFlick; + property bool isScrolling: (contentHeight - height) > 10 ? true : false; + clip: true; - Separator { } + ScrollBar.vertical: ScrollBar { + policy: flickView.isScrolling ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff; + parent: flickView.parent; + anchors.top: flickView.top; + anchors.right: flickView.right; + anchors.bottom: flickView.bottom; + anchors.rightMargin: -verticalScrollWidth; //compensate flickView's right margin + background: Item { + implicitWidth: verticalScrollWidth; + Rectangle { + color: hifi.colors.darkGray30; + radius: 4; + anchors { + fill: parent; + topMargin: -1; // Finesse size + bottomMargin: -2; + } + } + } + contentItem: Item { + implicitWidth: verticalScrollShaft; + Rectangle { + radius: verticalScrollShaft/2; + color: hifi.colors.white30; + anchors { + fill: parent; + leftMargin: 2; // Finesse size and position. + topMargin: 1; + bottomMargin: 1; + } + } + } + } - RowLayout { + Separator { + id: firstSeparator; + anchors.top: parent.top; + } + + Item { + id: switchesContainer; x: 2 * margins.paddings; width: parent.width; + // switch heights + 2 * top margins + height: (root.switchHeight) * 3 + 48; + anchors.top: firstSeparator.bottom; + anchors.topMargin: 10; // mute is in its own row - ColumnLayout { - id: columnOne - spacing: 24; - x: margins.paddings + Item { + id: switchContainer; + x: margins.paddings; + width: parent.width / 2; + height: parent.height; + anchors.left: parent.left; HifiControlsUit.Switch { id: muteMic; height: root.switchHeight; @@ -129,8 +191,12 @@ Rectangle { } HifiControlsUit.Switch { + id: noiseReductionSwitch; height: root.switchHeight; switchWidth: root.switchWidth; + anchors.top: muteMic.bottom; + anchors.topMargin: 24 + anchors.left: parent.left labelTextOn: "Noise Reduction"; backgroundOnColor: "#E3E3E3"; checked: AudioScriptingInterface.noiseReduction; @@ -144,6 +210,9 @@ Rectangle { id: pttSwitch height: root.switchHeight; switchWidth: root.switchWidth; + anchors.top: noiseReductionSwitch.bottom + anchors.topMargin: 24 + anchors.left: parent.left labelTextOn: qsTr("Push To Talk (T)"); backgroundOnColor: "#E3E3E3"; checked: (bar.currentIndex === 0) ? AudioScriptingInterface.pushToTalkDesktop : AudioScriptingInterface.pushToTalkHMD; @@ -164,12 +233,18 @@ Rectangle { } } - ColumnLayout { - spacing: 24; + Item { + id: additionalSwitchContainer + width: switchContainer.width - margins.paddings; + height: parent.height; + anchors.top: parent.top + anchors.left: switchContainer.right; HifiControlsUit.Switch { id: warnMutedSwitch height: root.switchHeight; switchWidth: root.switchWidth; + anchors.top: parent.top + anchors.left: parent.left labelTextOn: qsTr("Warn when muted"); backgroundOnColor: "#E3E3E3"; checked: AudioScriptingInterface.warnWhenMuted; @@ -184,6 +259,9 @@ Rectangle { id: audioLevelSwitch height: root.switchHeight; switchWidth: root.switchWidth; + anchors.top: warnMutedSwitch.bottom + anchors.topMargin: 24 + anchors.left: parent.left labelTextOn: qsTr("Audio Level Meter"); backgroundOnColor: "#E3E3E3"; checked: AvatarInputs.showAudioTools; @@ -197,6 +275,9 @@ Rectangle { id: stereoInput; height: root.switchHeight; switchWidth: root.switchWidth; + anchors.top: audioLevelSwitch.bottom + anchors.topMargin: 24 + anchors.left: parent.left labelTextOn: qsTr("Stereo input"); backgroundOnColor: "#E3E3E3"; checked: AudioScriptingInterface.isStereoInput; @@ -210,17 +291,20 @@ Rectangle { } Item { - anchors.left: parent.left + id: pttTextContainer + anchors.top: switchesContainer.bottom; + anchors.topMargin: 10; + anchors.left: parent.left; width: rightMostInputLevelPos; height: pttText.height; RalewayRegular { - id: pttText + id: pttText; x: margins.paddings; color: hifi.colors.white; width: rightMostInputLevelPos; height: paintedHeight; wrapMode: Text.WordWrap; - font.italic: true + font.italic: true; size: 16; text: (bar.currentIndex === 0) ? qsTr("Press and hold the button \"T\" to talk.") : @@ -228,28 +312,35 @@ Rectangle { } } - Separator { } + Separator { + id: secondSeparator; + anchors.top: pttTextContainer.bottom; + anchors.topMargin: 10; + } Item { + id: inputDeviceHeader x: margins.paddings; - width: parent.width - margins.paddings*2 - height: 36 + width: parent.width - margins.paddings*2; + height: 36; + anchors.top: secondSeparator.bottom; + anchors.topMargin: 10; HiFiGlyphs { - width: margins.sizeCheckBox + width: margins.sizeCheckBox; text: hifi.glyphs.mic; color: hifi.colors.white; - anchors.left: parent.left - anchors.leftMargin: -size/4 //the glyph has empty space at left about 25% + anchors.left: parent.left; + anchors.leftMargin: -size/4; //the glyph has empty space at left about 25% anchors.verticalCenter: parent.verticalCenter; size: 30; } RalewayRegular { anchors.verticalCenter: parent.verticalCenter; - width: margins.sizeText + margins.sizeLevel - anchors.left: parent.left - anchors.leftMargin: margins.sizeCheckBox + width: margins.sizeText + margins.sizeLevel; + anchors.left: parent.left; + anchors.leftMargin: margins.sizeCheckBox; size: 16; color: hifi.colors.white; text: qsTr("Choose input device"); @@ -257,12 +348,13 @@ Rectangle { } ListView { - id: inputView - width: parent.width - margins.paddings*2 + id: inputView; + width: parent.width - margins.paddings*2; + anchors.top: inputDeviceHeader.bottom; + anchors.topMargin: 10; x: margins.paddings - height: Math.min(150, contentHeight); + height: contentHeight; spacing: 4; - snapMode: ListView.SnapToItem; clip: true; model: AudioScriptingInterface.devices.input; delegate: Item { @@ -301,17 +393,28 @@ Rectangle { } } } + AudioControls.LoopbackAudio { + id: loopbackAudio x: margins.paddings + anchors.top: inputView.bottom; + anchors.topMargin: 10; visible: (bar.currentIndex === 1 && isVR) || (bar.currentIndex === 0 && !isVR); anchors { left: parent.left; leftMargin: margins.paddings } } - Separator {} + Separator { + id: thirdSeparator; + anchors.top: loopbackAudio.bottom; + anchors.topMargin: 10; + } Item { + id: outputDeviceHeader; + anchors.topMargin: 10; + anchors.top: thirdSeparator.bottom; x: margins.paddings; width: parent.width - margins.paddings*2 height: 36 @@ -341,9 +444,10 @@ Rectangle { id: outputView width: parent.width - margins.paddings*2 x: margins.paddings - height: Math.min(360 - inputView.height, contentHeight); + height: contentHeight; + anchors.top: outputDeviceHeader.bottom; + anchors.topMargin: 10; spacing: 4; - snapMode: ListView.SnapToItem; clip: true; model: AudioScriptingInterface.devices.output; delegate: Item { @@ -370,20 +474,22 @@ Rectangle { } Item { - id: gainContainer + id: avatarGainContainer x: margins.paddings; + anchors.top: outputView.bottom; + anchors.topMargin: 10; width: parent.width - margins.paddings*2 - height: gainSliderTextMetrics.height + height: avatarGainSliderTextMetrics.height HifiControlsUit.Slider { - id: gainSlider + id: avatarGainSlider anchors.right: parent.right height: parent.height width: 200 minimumValue: -60.0 maximumValue: 20.0 stepSize: 5 - value: Users.getAvatarGain(myAvatarUuid) + value: AudioScriptingInterface.getAvatarGain() onValueChanged: { updateMyAvatarGainFromQML(value, false); } @@ -399,7 +505,7 @@ Rectangle { // Do nothing. } onDoubleClicked: { - gainSlider.value = 0.0 + avatarGainSlider.value = 0.0 } onPressed: { // Pass through to Slider @@ -413,13 +519,13 @@ Rectangle { } } TextMetrics { - id: gainSliderTextMetrics - text: gainSliderText.text - font: gainSliderText.font + id: avatarGainSliderTextMetrics + text: avatarGainSliderText.text + font: avatarGainSliderText.font } RalewayRegular { // The slider for my card is special, it controls the master gain - id: gainSliderText; + id: avatarGainSliderText; text: "Avatar volume"; size: 16; anchors.left: parent.left; @@ -429,12 +535,133 @@ Rectangle { } } - AudioControls.PlaySampleSound { - x: margins.paddings + Item { + id: injectorGainContainer + x: margins.paddings; + width: parent.width - margins.paddings*2 + height: injectorGainSliderTextMetrics.height + anchors.top: avatarGainContainer.bottom; + anchors.topMargin: 10; - visible: (bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR); - anchors { left: parent.left; leftMargin: margins.paddings } + HifiControlsUit.Slider { + id: injectorGainSlider + anchors.right: parent.right + height: parent.height + width: 200 + minimumValue: -60.0 + maximumValue: 20.0 + stepSize: 5 + value: AudioScriptingInterface.getInjectorGain() + onValueChanged: { + updateInjectorGainFromQML(value, false); + } + onPressedChanged: { + if (!pressed) { + updateInjectorGainFromQML(value, false); + } + } + + MouseArea { + anchors.fill: parent + onWheel: { + // Do nothing. + } + onDoubleClicked: { + injectorGainSlider.value = 0.0 + } + onPressed: { + // Pass through to Slider + mouse.accepted = false + } + onReleased: { + // the above mouse.accepted seems to make this + // never get called, nonetheless... + mouse.accepted = false + } + } + } + TextMetrics { + id: injectorGainSliderTextMetrics + text: injectorGainSliderText.text + font: injectorGainSliderText.font + } + RalewayRegular { + id: injectorGainSliderText; + text: "Environment volume"; + size: 16; + anchors.left: parent.left; + color: hifi.colors.white; + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignTop; + } + } + + Item { + id: systemInjectorGainContainer + x: margins.paddings; + width: parent.width - margins.paddings*2 + height: systemInjectorGainSliderTextMetrics.height + anchors.top: injectorGainContainer.bottom; + anchors.topMargin: 10; + + HifiControlsUit.Slider { + id: systemInjectorGainSlider + anchors.right: parent.right + height: parent.height + width: 200 + minimumValue: -60.0 + maximumValue: 20.0 + stepSize: 5 + value: AudioScriptingInterface.getSystemInjectorGain() + onValueChanged: { + updateSystemInjectorGainFromQML(value, false); + } + onPressedChanged: { + if (!pressed) { + updateSystemInjectorGainFromQML(value, false); + } + } + + MouseArea { + anchors.fill: parent + onWheel: { + // Do nothing. + } + onDoubleClicked: { + systemInjectorGainSlider.value = 0.0 + } + onPressed: { + // Pass through to Slider + mouse.accepted = false + } + onReleased: { + // the above mouse.accepted seems to make this + // never get called, nonetheless... + mouse.accepted = false + } + } + } + TextMetrics { + id: systemInjectorGainSliderTextMetrics + text: systemInjectorGainSliderText.text + font: systemInjectorGainSliderText.font + } + RalewayRegular { + id: systemInjectorGainSliderText; + text: "System Sound volume"; + size: 16; + anchors.left: parent.left; + color: hifi.colors.white; + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignTop; + } + } + + AudioControls.PlaySampleSound { + id: playSampleSound + x: margins.paddings + anchors.top: systemInjectorGainContainer.bottom; + anchors.topMargin: 10; } } } diff --git a/interface/resources/qml/hifi/audio/AudioTabButton.qml b/interface/resources/qml/hifi/audio/AudioTabButton.qml index 32331ccb6e..c81377e524 100644 --- a/interface/resources/qml/hifi/audio/AudioTabButton.qml +++ b/interface/resources/qml/hifi/audio/AudioTabButton.qml @@ -16,7 +16,7 @@ import stylesUit 1.0 TabButton { id: control - font.pixelSize: height / 2 + font.pixelSize: 14 HifiConstants { id: hifi; } diff --git a/interface/resources/qml/hifi/audio/LoopbackAudio.qml b/interface/resources/qml/hifi/audio/LoopbackAudio.qml index 8ec0ffc496..db0614dfdc 100644 --- a/interface/resources/qml/hifi/audio/LoopbackAudio.qml +++ b/interface/resources/qml/hifi/audio/LoopbackAudio.qml @@ -17,17 +17,17 @@ import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit RowLayout { - property bool audioLoopedBack: AudioScriptingInterface.getServerEcho(); + property bool audioLoopedBack: AudioScriptingInterface.getLocalEcho(); function startAudioLoopback() { if (!audioLoopedBack) { audioLoopedBack = true; - AudioScriptingInterface.setServerEcho(true); + AudioScriptingInterface.setLocalEcho(true); } } function stopAudioLoopback() { if (audioLoopedBack) { audioLoopedBack = false; - AudioScriptingInterface.setServerEcho(false); + AudioScriptingInterface.setLocalEcho(false); } } @@ -44,8 +44,11 @@ RowLayout { } HifiControlsUit.Button { - text: audioLoopedBack ? qsTr("STOP TESTING YOUR VOICE") : qsTr("TEST YOUR VOICE"); + text: audioLoopedBack ? qsTr("STOP TESTING VOICE") : qsTr("TEST YOUR VOICE"); color: audioLoopedBack ? hifi.buttons.red : hifi.buttons.blue; + fontSize: 15; + width: 200; + height: 32; onClicked: { if (audioLoopedBack) { loopbackTimer.stop(); @@ -57,11 +60,11 @@ RowLayout { } } - RalewayRegular { - Layout.leftMargin: 2; - size: 14; - color: "white"; - font.italic: true - text: audioLoopedBack ? qsTr("Speak in your input") : ""; - } +// RalewayRegular { +// Layout.leftMargin: 2; +// size: 14; +// color: "white"; +// font.italic: true +// text: audioLoopedBack ? qsTr("Speak in your input") : ""; +// } } diff --git a/interface/resources/qml/hifi/audio/PlaySampleSound.qml b/interface/resources/qml/hifi/audio/PlaySampleSound.qml index b9d9727dab..033af99d04 100644 --- a/interface/resources/qml/hifi/audio/PlaySampleSound.qml +++ b/interface/resources/qml/hifi/audio/PlaySampleSound.qml @@ -56,16 +56,19 @@ RowLayout { HifiConstants { id: hifi; } HifiControlsUit.Button { - text: isPlaying ? qsTr("STOP TESTING YOUR SOUND") : qsTr("TEST YOUR SOUND"); + text: isPlaying ? qsTr("STOP TESTING") : qsTr("TEST YOUR SOUND"); color: isPlaying ? hifi.buttons.red : hifi.buttons.blue; onClicked: isPlaying ? stopSound() : playSound(); + fontSize: 15; + width: 200; + height: 32; } - RalewayRegular { - Layout.leftMargin: 2; - size: 14; - color: "white"; - font.italic: true - text: isPlaying ? qsTr("Listen to your output") : ""; - } +// RalewayRegular { +// Layout.leftMargin: 2; +// size: 14; +// color: "white"; +// font.italic: true +// text: isPlaying ? qsTr("Listen to your output") : ""; +// } } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml index 8afc60fd90..278ce36362 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml @@ -133,7 +133,7 @@ Item { states: [ State { name: AvatarPackagerState.main - PropertyChanges { target: avatarPackagerHeader; title: qsTr("Avatar Packager"); docsEnabled: true; backButtonVisible: false } + PropertyChanges { target: avatarPackagerHeader; title: qsTr("Avatar Packager"); docsEnabled: true; videoEnabled: true; backButtonVisible: false } PropertyChanges { target: avatarPackagerMain; visible: true } PropertyChanges { target: avatarPackagerFooter; content: avatarPackagerMain.footer } }, @@ -229,7 +229,11 @@ Item { } function openDocs() { - Qt.openUrlExternally("https://docs.highfidelity.com/create/avatars/create-avatars#how-to-package-your-avatar"); + Qt.openUrlExternally("https://docs.highfidelity.com/create/avatars/package-avatar.html"); + } + + function openVideo() { + Qt.openUrlExternally("https://youtu.be/zrkEowu_yps"); } AvatarPackagerHeader { @@ -243,6 +247,9 @@ Item { onDocsButtonClicked: { avatarPackager.openDocs(); } + onVideoButtonClicked: { + avatarPackager.openVideo(); + } } Item { diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml index 25201bf81e..31528a8557 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml @@ -13,6 +13,7 @@ ShadowRectangle { property string title: qsTr("Avatar Packager") property alias docsEnabled: docs.visible + property alias videoEnabled: video.visible property bool backButtonVisible: true // If false, is not visible and does not take up space property bool backButtonEnabled: true // If false, is not visible but does not affect space property bool canRename: false @@ -24,6 +25,7 @@ ShadowRectangle { signal backButtonClicked signal docsButtonClicked + signal videoButtonClicked RalewayButton { id: back @@ -126,6 +128,20 @@ ShadowRectangle { } } + RalewayButton { + id: video + visible: false + size: 28 + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: docs.left + anchors.rightMargin: 16 + + text: qsTr("Video") + + onClicked: videoButtonClicked() + } + RalewayButton { id: docs visible: false @@ -137,8 +153,6 @@ ShadowRectangle { text: qsTr("Docs") - onClicked: { - docsButtonClicked(); - } + onClicked: docsButtonClicked() } } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml index bf8c06d1b3..e5bffa7829 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml @@ -339,8 +339,8 @@ Item { visible: AvatarPackagerCore.currentAvatarProject && AvatarPackagerCore.currentAvatarProject.hasErrors anchors { - top: notForSaleMessage.bottom - topMargin: 16 + top: notForSaleMessage.visible ? notForSaleMessage.bottom : infoMessage .bottom + bottom: showFilesText.top horizontalCenter: parent.horizontalCenter } diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml index 626ac4da65..e159344d5c 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml @@ -2248,6 +2248,7 @@ Item { if (sendAssetStep.selectedRecipientUserName === "") { console.log("SendAsset: Script didn't specify a recipient username!"); sendAssetHome.visible = false; + root.nextActiveView = 'paymentFailure'; return; } diff --git a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml index 7dcdf9b434..619547ef43 100644 --- a/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml +++ b/interface/resources/qml/hifi/commerce/marketplace/Marketplace.qml @@ -664,7 +664,7 @@ Rectangle { text: "LOG IN" onClicked: { - sendToScript({method: 'needsLogIn_loginClicked'}); + sendToScript({method: 'marketplace_loginClicked'}); } } diff --git a/interface/resources/qml/hifi/dialogs/Audio.qml b/interface/resources/qml/hifi/dialogs/Audio.qml deleted file mode 100644 index 4ce9e14c42..0000000000 --- a/interface/resources/qml/hifi/dialogs/Audio.qml +++ /dev/null @@ -1,27 +0,0 @@ -// -// Audio.qml -// -// Created by Zach Pomerantz on 6/12/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import "../../windows" -import "../audio" - -ScrollingWindow { - id: root; - - resizable: true; - destroyOnHidden: true; - width: 400; - height: 577; - minSize: Qt.vector2d(400, 500); - - Audio { id: audio; width: root.width } - - objectName: "AudioDialog"; - title: audio.title; -} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 635932ea1c..47f3b774b2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1206,10 +1206,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this]() { - auto tabletScriptingInterface = DependencyManager::getProperty | Type | Description |
---|---|---|
id | Uuid | Entity ID. |
properties | {@link Entities.EntityProperties} | Entity properties. |
true
to enable flow on the joint, otherwise false
.
+ * @property {number} [radius=0.01] - The thickness of segments and knots (needed for collisions).
+ * @property {number} [gravity=-0.0096] - Y-value of the gravity vector.
+ * @property {number} [inertia=0.8] - Rotational inertia multiplier.
+ * @property {number} [damping=0.85] - The amount of damping on joint oscillation.
+ * @property {number} [stiffness=0.0] - The stiffness of each thread.
+ * @property {number} [delta=0.55] - Delta time for every integration step.
+ */
+/**jsdoc
+ * Collision options to use in the flow simulation of a joint.
+ * @typedef {object} MyAvatar.FlowCollisionsOptions
+ * @property {string} [type="sphere"] - Currently, only "sphere"
is supported.
+ * @property {number} [radius=0.05] - Collision sphere radius.
+ * @property {number} [offset=Vec3.ZERO] - Offset of the collision sphere from the joint.
+ */
void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& physicsConfig, const QVariantMap& collisionsConfig) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "useFlow",
@@ -5419,7 +5463,7 @@ void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& phys
}
auto collisionJoints = collisionsConfig.keys();
if (collisionJoints.size() > 0) {
- collisionSystem.resetCollisions();
+ collisionSystem.clearSelfCollisions();
for (auto &jointName : collisionJoints) {
int jointIndex = getJointIndex(jointName);
FlowCollisionSettings collisionsSettings;
@@ -5434,9 +5478,43 @@ void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& phys
collisionSystem.addCollisionSphere(jointIndex, collisionsSettings);
}
}
+ flow.updateScale();
}
}
+/**jsdoc
+ * Flow options currently used in flow simulation.
+ * @typedef {object} MyAvatar.FlowData
+ * @property {boolean} initialized - true
if flow has been initialized for the current avatar, false
+ * if it hasn't.
+ * @property {boolean} active - true
if flow is enabled, false
if it isn't.
+ * @property {boolean} colliding - true
if collisions are enabled, false
if they aren't.
+ * @property {ObjectThreadName
and value as an array of the indexes of all the joints in the thread.
+ */
+/**jsdoc
+ * A set of physics options currently used in flow simulation.
+ * @typedef {object} MyAvatar.FlowPhysicsData
+ * @property {boolean} active - true
to enable flow on the joint, otherwise false
.
+ * @property {number} radius - The thickness of segments and knots. (Needed for collisions.)
+ * @property {number} gravity - Y-value of the gravity vector.
+ * @property {number} inertia - Rotational inertia multiplier.
+ * @property {number} damping - The amount of damping on joint oscillation.
+ * @property {number} stiffness - The stiffness of each thread.
+ * @property {number} delta - Delta time for every integration step.
+ * @property {number[]} jointIndices - The indexes of the joints the options are applied to.
+ */
+/**jsdoc
+ * A set of collision options currently used in flow simulation.
+ * @typedef {object} MyAvatar.FlowCollisionsData
+ * @property {number} radius - Collision sphere radius.
+ * @property {number} offset - Offset of the collision sphere from the joint.
+ * @property {number} jointIndex - The index of the joint the options are applied to.
+ */
QVariantMap MyAvatar::getFlowData() {
QVariantMap result;
if (QThread::currentThread() != thread()) {
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 2f1ff58dcb..edb686a6a6 100755
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -60,7 +60,9 @@ class MyAvatar : public Avatar {
/**jsdoc
* Your avatar is your in-world representation of you. The MyAvatar
API is used to manipulate the avatar.
* For example, you can customize the avatar's appearance, run custom avatar animations,
- * change the avatar's position within the domain, or manage the avatar's collisions with other objects.
+ * change the avatar's position within the domain, or manage the avatar's collisions with the environment and other avatars.
+ *
+ * For assignment client scripts, see {@link Avatar}.
* * @namespace MyAvatar * @@ -68,7 +70,59 @@ class MyAvatar : public Avatar { * @hifi-client-entity * @hifi-avatar * + * @comment IMPORTANT: This group of properties is copied from AvatarData.h; they should NOT be edited here. + * @property {Vec3} position - The position of the avatar. + * @property {number} scale=1.0 - The scale of the avatar. The value can be set to anything between0.005
and
+ * 1000.0
. When the scale value is fetched, it may temporarily be further limited by the domain's settings.
+ * @property {number} density - The density of the avatar in kg/m3. The density is used to work out its mass in
+ * the application of physics. Read-only.
+ * @property {Vec3} handPosition - A user-defined hand position, in world coordinates. The position moves with the avatar
+ * but is otherwise not used or changed by Interface.
+ * @property {number} bodyYaw - The left or right rotation about an axis running from the head to the feet of the avatar.
+ * Yaw is sometimes called "heading".
+ * @property {number} bodyPitch - The rotation about an axis running from shoulder to shoulder of the avatar. Pitch is
+ * sometimes called "elevation".
+ * @property {number} bodyRoll - The rotation about an axis running from the chest to the back of the avatar. Roll is
+ * sometimes called "bank".
+ * @property {Quat} orientation - The orientation of the avatar.
+ * @property {Quat} headOrientation - The orientation of the avatar's head.
+ * @property {number} headPitch - The rotation about an axis running from ear to ear of the avatar's head. Pitch is
+ * sometimes called "elevation".
+ * @property {number} headYaw - The rotation left or right about an axis running from the base to the crown of the avatar's
+ * head. Yaw is sometimes called "heading".
+ * @property {number} headRoll - The rotation about an axis running from the nose to the back of the avatar's head. Roll is
+ * sometimes called "bank".
+ * @property {Vec3} velocity - The current velocity of the avatar.
+ * @property {Vec3} angularVelocity - The current angular velocity of the avatar.
+ * @property {number} audioLoudness - The instantaneous loudness of the audio input that the avatar is injecting into the
+ * domain.
+ * @property {number} audioAverageLoudness - The rolling average loudness of the audio input that the avatar is injecting
+ * into the domain.
+ * @property {string} displayName - The avatar's display name.
+ * @property {string} sessionDisplayName - displayName's
sanitized and default version defined by the avatar
+ * mixer rather than Interface clients. The result is unique among all avatars present in the domain at the time.
+ * @property {boolean} lookAtSnappingEnabled=true - true
if the avatar's eyes snap to look at another avatar's
+ * eyes when the other avatar is in the line of sight and also has lookAtSnappingEnabled == true
.
+ * @property {string} skeletonModelURL - The avatar's FST file.
+ * @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.position
for use by QML.
+ *
* @property {boolean} shouldRenderLocally=true - If true
then your avatar is rendered for you in Interface,
* otherwise it is not rendered for you (but it is still rendered for other users).
* @property {Vec3} motorVelocity=Vec3.ZERO - The target velocity of your avatar to be achieved by a scripted motor.
@@ -83,107 +137,164 @@ class MyAvatar : public Avatar {
* by the audio mixer, so all audio effectively plays back at a 24khz. 48kHz RAW files are also supported.
* @property {number} audioListenerMode=0 - Specifies the listening position when hearing spatialized audio. Must be one
* of the following property values:audioListenerModeHead
audioListenerModeCamera
audioListenerModeCustom
+ * Myavatar.audioListenerModeHead
Myavatar.audioListenerModeCamera
Myavatar.audioListenerModeCustom
* @property {number} audioListenerModeHead=0 - The audio listening position is at the avatar's head. Read-only.
* @property {number} audioListenerModeCamera=1 - The audio listening position is at the camera. Read-only.
* @property {number} audioListenerModeCustom=2 - The audio listening position is at a the position specified by set by the
* customListenPosition
and customListenOrientation
property values. Read-only.
- * @property {boolean} hasScriptedBlendshapes=false - Blendshapes will be transmitted over the network if set to true.
- * @property {boolean} hasProceduralBlinkFaceMovement=true - procedural blinking will be turned on if set to true.
- * @property {boolean} hasProceduralEyeFaceMovement=true - procedural eye movement will be turned on if set to true.
- * @property {boolean} hasAudioEnabledFaceMovement=true - If set to true, voice audio will move the mouth Blendshapes while MyAvatar.hasScriptedBlendshapes is enabled.
* @property {Vec3} customListenPosition=Vec3.ZERO - The listening position used when the audioListenerMode
* property value is audioListenerModeCustom
.
- * @property {Quat} customListenOrientation=Quat.IDENTITY - The listening orientation used when the
+ * @property {Quat} customListenOrientation=Quat.IDENTITY - The listening orientation used when the
* audioListenerMode
property value is audioListenerModeCustom
.
+ * @property {boolean} hasScriptedBlendshapes=false - true
to transmit blendshapes over the network.true
if procedural blinking is turned on.
+ * @property {boolean} hasProceduralEyeFaceMovement=true - true
if procedural eye movement is turned on.
+ * @property {boolean} hasAudioEnabledFaceMovement=true - true
to move the mouth blendshapes with voice audio
+ * when MyAvatar.hasScriptedBlendshapes
is enabled.
+ * @property {number} rotationRecenterFilterLength - Configures how quickly the avatar root rotates to recenter its facing
+ * direction to match that of the user's torso based on head and hands orientation. A smaller value makes the
+ * recentering happen more quickly. The minimum value is 0.01
.
+ * @property {number} rotationThreshold - The angle in radians that the user's torso facing direction (based on head and
+ * hands orientation) can differ from that of the avatar before the avatar's root is rotated to match the user's torso.
+ * @property {boolean} enableStepResetRotation - If true
then after the user's avatar takes a step, the
+ * avatar's root immediately rotates to recenter its facing direction to match that of the user's torso based on head
+ * and hands orientation.
+ * @property {boolean} enableDrawAverageFacing - If true
, debug graphics are drawn that show the average
+ * facing direction of the user's torso (based on head and hands orientation). This can be useful if you want to try
+ * out different filter lengths and thresholds.
+ *
* @property {Vec3} leftHandPosition - The position of the left hand in avatar coordinates if it's being positioned by
* controllers, otherwise {@link Vec3(0)|Vec3.ZERO}. Read-only.
* @property {Vec3} rightHandPosition - The position of the right hand in avatar coordinates if it's being positioned by
* controllers, otherwise {@link Vec3(0)|Vec3.ZERO}. Read-only.
-
- * @property {Vec3} leftHandTipPosition - The position 30cm offset from the left hand in avatar coordinates if it's being
- * positioned by controllers, otherwise {@link Vec3(0)|Vec3.ZERO}. Read-only.
- * @property {Vec3} rightHandTipPosition - The position 30cm offset from the right hand in avatar coordinates if it's being
- * positioned by controllers, otherwise {@link Vec3(0)|Vec3.ZERO}. Read-only.
- * @property {Pose} leftHandPose - The pose of the left hand as determined by the hand controllers. Read-only.
- * @property {Pose} rightHandPose - The pose right hand position as determined by the hand controllers. Read-only.
- * @property {Pose} leftHandTipPose - The pose of the left hand as determined by the hand controllers, with the position
- * by 30cm. Read-only.
- * @property {Pose} rightHandTipPose - The pose of the right hand as determined by the hand controllers, with the position
- * by 30cm. Read-only.
- * @property {boolean} centerOfGravityModelEnabled=true - If true
then the avatar hips are placed according to the center of
- * gravity model that balance the center of gravity over the base of support of the feet. Setting the value false
- * will result in the default behaviour where the hips are placed under the head.
- * @property {boolean} hmdLeanRecenterEnabled=true - If true
then the avatar is re-centered to be under the
+ * @property {Vec3} leftHandTipPosition - The position 0.3m in front of the left hand's position, in the direction along the
+ * palm, in avatar coordinates. If the hand isn't being positioned by a controller, the value is
+ * {@link Vec3(0)|Vec3.ZERO}. Read-only.
+ * @property {Vec3} rightHandTipPosition - The position 0.3m in front of the right hand's position, in the direction along
+ * the palm, in avatar coordinates. If the hand isn't being positioned by a controller, the value is
+ * {@link Vec3(0)|Vec3.ZERO}. Read-only.
+ *
+ * @property {Pose} leftHandPose - The left hand's pose as determined by the hand controllers, relative to the avatar.
+ * Read-only.
+ * @property {Pose} rightHandPose - The right hand's pose as determined by the hand controllers, relative to the avatar.
+ * Read-only.
+ * @property {Pose} leftHandTipPose - The left hand's pose as determined by the hand controllers, relative to the avatar,
+ * with the position adjusted by 0.3m along the direction of the palm. Read-only.
+ * @property {Pose} rightHandTipPose - The right hand's pose as determined by the hand controllers, relative to the avatar,
+ * with the position adjusted by 0.3m along the direction of the palm. Read-only.
+ *
+ * @property {number} energy - Deprecated: This property will be removed from the API.
+ * @property {boolean} isAway - true
if your avatar is away (i.e., inactive), false
if it is
+ * active.
+ *
+ * @property {boolean} centerOfGravityModelEnabled=true - true
if the avatar hips are placed according to
+ * the center of gravity model that balances the center of gravity over the base of support of the feet. Set the
+ * value to false
for default behavior where the hips are positioned under the head.
+ * @property {boolean} hmdLeanRecenterEnabled=true - true
IF the avatar is re-centered to be under the
* head's position. In room-scale VR, this behavior is what causes your avatar to follow your HMD as you walk around
* the room. Setting the value false
is useful if you want to pin the avatar to a fixed position.
- * @property {boolean} collisionsEnabled - Set to true
to enable collisions for the avatar, false
- * to disable collisions. May return true
even though the value was set false
because the
- * zone may disallow collisionless avatars.
- * @property {boolean} characterControllerEnabled - Synonym of collisionsEnabled
.
+ * @property {boolean} collisionsEnabled - Set to true
to enable the avatar to collide with the environment,
+ * false
to disable collisions with the environment. May return true
even though the value
+ * was set false
because the zone may disallow collisionless avatars.
+ * @property {boolean} otherAvatarsCollisionsEnabled - Set to true
to enable the avatar to collide with other
+ * avatars, false
to disable collisions with other avatars.
+ * @property {boolean} characterControllerEnabled - Synonym of collisionsEnabled
.collisionsEnabled
instead.
* @property {boolean} useAdvancedMovementControls - Returns and sets the value of the Interface setting, Settings >
- * Walking and teleporting. Note: Setting the value has no effect unless Interface is restarted.
- * @property {boolean} showPlayArea - Returns and sets the value of the Interface setting, Settings > Show room boundaries
- * while teleporting. Note: Setting the value has no effect unless Interface is restarted.
- * @property {number} yawSpeed=75
- * @property {number} pitchSpeed=50
+ * Controls > Walking. Note: Setting the value has no effect unless Interface is restarted.
+ * @property {boolean} showPlayArea - Returns and sets the value of the Interface setting, Settings > Controls > Show room
+ * boundaries while teleporting.true
, the roll angle of your HMD turns your avatar
* while flying.
* @property {number} hmdRollControlDeadZone=8 - The amount of HMD roll, in degrees, required before your avatar turns if
* hmdRollControlEnabled
is enabled.
- * @property {number} hmdRollControlRate If hmdRollControlEnabled is true, this value determines the maximum turn rate of
- * your avatar when rolling your HMD in degrees per second.
+ * @property {number} hmdRollControlRate If MyAvatar.hmdRollControlEnabled
is true, this value determines the
+ * maximum turn rate of your avatar when rolling your HMD in degrees per second.
+ *
* @property {number} userHeight=1.75 - The height of the user in sensor space.
* @property {number} userEyeHeight=1.65 - The estimated height of the user's eyes in sensor space. Read-only.
+ *
* @property {Uuid} SELF_ID - UUID representing "my avatar". Only use for local-only entities in situations
* where MyAvatar.sessionUUID is not available (e.g., if not connected to a domain). Note: Likely to be deprecated.
* Read-only.
- * @property {number} walkSpeed
- * @property {number} walkBackwardSpeed
- * @property {number} sprintSpeed
- * @property {number} isInSittingState
- * @property {number} userRecenterModel
*
- * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the
- * registration point of the 3D model.
+ * @property {number} walkSpeed - The walk speed of your avatar.
+ * @property {number} walkBackwardSpeed - The walk backward speed of your avatar.
+ * @property {number} sprintSpeed - The sprint speed of your avatar.
+ * @property {MyAvatar.SitStandModelType} userRecenterModel - Controls avatar leaning and recentering behavior.
+ * @property {number} isInSittingState - true
if your avatar is sitting (avatar leaning is disabled,
+ * recenntering is enabled), false
if it is standing (avatar leaning is enabled, and avatar recenters if it
+ * leans too far). If userRecenterModel == 2
(i.e., auto) the property value automatically updates as the
+ * user sits or stands, unless isSitStandStateLocked == true
. Setting the property value overrides the
+ * current siting / standing state, which is updated when the user next sits or stands unless
+ * isSitStandStateLocked == true
.
+ * @property {boolean} isSitStandStateLocked - true
to lock the avatar sitting/standing state, i.e., use this
+ * to disable automatically changing state.
+ * @property {boolean} allowTeleporting - true
if teleporting is enabled in the Interface settings,
+ * false
if it isn't. Read-only.
*
- * @property {Vec3} position
- * @property {number} scale - Returns the clamped scale of the avatar.
- * @property {number} density Read-only.
- * @property {Vec3} handPosition
- * @property {number} bodyYaw - The rotation left or right about an axis running from the head to the feet of the avatar.
- * Yaw is sometimes called "heading".
- * @property {number} bodyPitch - The rotation about an axis running from shoulder to shoulder of the avatar. Pitch is
- * sometimes called "elevation".
- * @property {number} bodyRoll - The rotation about an axis running from the chest to the back of the avatar. Roll is
- * sometimes called "bank".
- * @property {Quat} orientation
- * @property {Quat} headOrientation - The orientation of the avatar's head.
- * @property {number} headPitch - The rotation about an axis running from ear to ear of the avatar's head. Pitch is
- * sometimes called "elevation".
- * @property {number} headYaw - The rotation left or right about an axis running from the base to the crown of the avatar's
- * head. Yaw is sometimes called "heading".
- * @property {number} headRoll - The rotation about an axis running from the nose to the back of the avatar's head. Roll is
- * sometimes called "bank".
- * @property {Vec3} velocity
- * @property {Vec3} angularVelocity
- * @property {number} audioLoudness
- * @property {number} audioAverageLoudness
- * @property {string} displayName
- * @property {string} sessionDisplayName - Sanitized, defaulted version displayName that is defined by the AvatarMixer
- * rather than by Interface clients. The result is unique among all avatars present at the time.
- * @property {boolean} lookAtSnappingEnabled
- * @property {string} skeletonModelURL
- * @property {AttachmentData[]} attachmentData
- * @property {string[]} jointNames - The list of joints in the current avatar model. Read-only.
- * @property {Uuid} sessionUUID Read-only.
- * @property {Mat4} sensorToWorldMatrix Read-only.
- * @property {Mat4} controllerLeftHandMatrix Read-only.
- * @property {Mat4} controllerRightHandMatrix Read-only.
- * @property {number} sensorToWorldScale Read-only.
+ * @borrows Avatar.getDomainMinScale as getDomainMinScale
+ * @borrows Avatar.getDomainMaxScale as getDomainMaxScale
+ * @borrows Avatar.getEyeHeight as getEyeHeight
+ * @borrows Avatar.getHeight as getHeight
+ * @borrows Avatar.setHandState as setHandState
+ * @borrows Avatar.getHandState as getHandState
+ * @borrows Avatar.setRawJointData as setRawJointData
+ * @borrows Avatar.setJointData as setJointData
+ * @borrows Avatar.setJointRotation as setJointRotation
+ * @borrows Avatar.setJointTranslation as setJointTranslation
+ * @borrows Avatar.clearJointData as clearJointData
+ * @borrows Avatar.isJointDataValid as isJointDataValid
+ * @borrows Avatar.getJointRotation as getJointRotation
+ * @borrows Avatar.getJointTranslation as getJointTranslation
+ * @borrows Avatar.getJointRotations as getJointRotations
+ * @borrows Avatar.getJointTranslations as getJointTranslations
+ * @borrows Avatar.setJointRotations as setJointRotations
+ * @borrows Avatar.setJointTranslations as setJointTranslations
+ * @borrows Avatar.clearJointsData as clearJointsData
+ * @borrows Avatar.getJointIndex as getJointIndex
+ * @borrows Avatar.getJointNames as getJointNames
+ * @borrows Avatar.setBlendshape as setBlendshape
+ * @borrows Avatar.getAttachmentsVariant as getAttachmentsVariant
+ * @borrows Avatar.setAttachmentsVariant as setAttachmentsVariant
+ * @borrows Avatar.updateAvatarEntity as updateAvatarEntity
+ * @borrows Avatar.clearAvatarEntity as clearAvatarEntity
+ * @borrows Avatar.setForceFaceTrackerConnected as setForceFaceTrackerConnected
+ * @borrows Avatar.getAttachmentData as getAttachmentData
+ * @borrows Avatar.setAttachmentData as setAttachmentData
+ * @borrows Avatar.attach as attach
+ * @borrows Avatar.detachOne as detachOne
+ * @borrows Avatar.detachAll as detachAll
+ * @comment Avatar.getAvatarEntityData as getAvatarEntityData - Don't borrow because implementation is different.
+ * @comment Avatar.setAvatarEntityData as setAvatarEntityData - Don't borrow because implementation is different.
+ * @borrows Avatar.getSensorToWorldMatrix as getSensorToWorldMatrix
+ * @borrows Avatar.getSensorToWorldScale as getSensorToWorldScale
+ * @borrows Avatar.getControllerLeftHandMatrix as getControllerLeftHandMatrix
+ * @borrows Avatar.getControllerRightHandMatrix as getControllerRightHandMatrix
+ * @borrows Avatar.getDataRate as getDataRate
+ * @borrows Avatar.getUpdateRate as getUpdateRate
+ * @borrows Avatar.displayNameChanged as displayNameChanged
+ * @borrows Avatar.sessionDisplayNameChanged as sessionDisplayNameChanged
+ * @borrows Avatar.skeletonModelURLChanged as skeletonModelURLChanged
+ * @borrows Avatar.lookAtSnappingChanged as lookAtSnappingChanged
+ * @borrows Avatar.sessionUUIDChanged as sessionUUIDChanged
+ * @borrows Avatar.sendAvatarDataPacket as sendAvatarDataPacket
+ * @borrows Avatar.sendIdentityPacket as sendIdentityPacket
+ * @borrows Avatar.setSessionUUID as setSessionUUID
+ * @comment Avatar.getAbsoluteJointRotationInObjectFrame as getAbsoluteJointRotationInObjectFrame - Don't borrow because implementation is different.
+ * @comment Avatar.getAbsoluteJointTranslationInObjectFrame as getAbsoluteJointTranslationInObjectFrame - Don't borrow because implementation is different.
+ * @comment Avatar.setAbsoluteJointRotationInObjectFrame as setAbsoluteJointRotationInObjectFrame - Don't borrow because implementation is different.
+ * @comment Avatar.setAbsoluteJointTranslationInObjectFrame as setAbsoluteJointTranslationInObjectFrame - Don't borrow because implementation is different.
+ * @borrows Avatar.getTargetScale as getTargetScale
+ * @borrows Avatar.resetLastSent as resetLastSent
*/
// FIXME: `glm::vec3 position` is not accessible from QML, so this exposes position in a QML-native type
Q_PROPERTY(QVector3D qmlPosition READ getQmlPosition)
@@ -196,11 +307,11 @@ class MyAvatar : public Avatar {
Q_PROPERTY(QString motorMode READ getScriptedMotorMode WRITE setScriptedMotorMode)
Q_PROPERTY(QString collisionSoundURL READ getCollisionSoundURL WRITE setCollisionSoundURL)
Q_PROPERTY(AudioListenerMode audioListenerMode READ getAudioListenerMode WRITE setAudioListenerMode)
- Q_PROPERTY(glm::vec3 customListenPosition READ getCustomListenPosition WRITE setCustomListenPosition)
- Q_PROPERTY(glm::quat customListenOrientation READ getCustomListenOrientation WRITE setCustomListenOrientation)
Q_PROPERTY(AudioListenerMode audioListenerModeHead READ getAudioListenerModeHead)
Q_PROPERTY(AudioListenerMode audioListenerModeCamera READ getAudioListenerModeCamera)
Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom)
+ Q_PROPERTY(glm::vec3 customListenPosition READ getCustomListenPosition WRITE setCustomListenPosition)
+ Q_PROPERTY(glm::quat customListenOrientation READ getCustomListenOrientation WRITE setCustomListenOrientation)
Q_PROPERTY(bool hasScriptedBlendshapes READ getHasScriptedBlendshapes WRITE setHasScriptedBlendshapes)
Q_PROPERTY(bool hasProceduralBlinkFaceMovement READ getHasProceduralBlinkFaceMovement WRITE setHasProceduralBlinkFaceMovement)
Q_PROPERTY(bool hasProceduralEyeFaceMovement READ getHasProceduralEyeFaceMovement WRITE setHasProceduralEyeFaceMovement)
@@ -260,6 +371,40 @@ class MyAvatar : public Avatar {
using TimePoint = Clock::time_point;
public:
+
+ /**jsdoc
+ * Logical keys that drive your avatar and camera.
+ *Value | Name | Description |
---|---|---|
0 | TRANSLATE_X | Move the user's avatar in the direction of its x-axis, if the + * camera isn't in independent or mirror modes. |
1 | TRANSLATE_Y | Move the user's avatar in the direction of its y-axis, if the + * camera isn't in independent or mirror modes. |
2 | TRANSLATE_Z | Move the user's avatar in the direction of its z-axis, if the + * camera isn't in independent or mirror modes |
3 | YAW | Rotate the user's avatar about its y-axis at a rate proportional to the + * control value, if the camera isn't in independent or mirror modes. |
4 | STEP_TRANSLATE_X | No action. |
5 | STEP_TRANSLATE_Y | No action. |
6 | STEP_TRANSLATE_Z | No action. |
7 | STEP_YAW | Rotate the user's avatar about its y-axis in a step increment, if + * the camera isn't in independent or mirror modes. |
8 | PITCH | Rotate the user's avatar head and attached camera about its negative + * x-axis (i.e., positive values pitch down) at a rate proportional to the control value, if the camera isn't in HMD, + * independent, or mirror modes. |
9 | ZOOM | Zoom the camera in or out. |
10 | DELTA_YAW | Rotate the user's avatar about its y-axis by an amount proportional + * to the control value, if the camera isn't in independent or mirror modes. |
11 | DELTA_PITCH | Rotate the user's avatar head and attached camera about its + * negative x-axis (i.e., positive values pitch down) by an amount proportional to the control value, if the camera + * isn't in HMD, independent, or mirror modes. |
Specifies different avatar leaning and recentering behaviors.
+ *Value | Name | Description |
---|---|---|
0 | ForceSit | Assumes the user is seated in the real world. Disables avatar + * leaning regardless of what the avatar is doing in the virtual world (i.e., avatar always recenters). |
1 | ForceStand | Assumes the user is standing in the real world. Enables avatar + * leaning regardless of what the avatar is doing in the virtual world (i.e. avatar leans, then if leans too far it + * recenters). |
2 | Auto | Interface detects when the user is standing or seated in the real world. + * Avatar leaning is disabled when the user is sitting (i.e., avatar always recenters), and avatar leaning is enabled + * when the user is standing (i.e., avatar leans, then if leans too far it recenters). |
3 | DisableHMDLean | Both avatar leaning and recentering are disabled regardless of
+ * what the user is doing in the real world and no matter what their avatar is doing in the virtual world. Enables
+ * the avatar to sit on the floor when the user sits on the floor. Note: Experimental. |
The internal inverse-kinematics system maintains a record of which joints are "locked". Sometimes it is useful to + * forget this history to prevent contorted joints, e.g., after finishing with an override animation.
* @function MyAvatar.clearIKJointLimitHistory */ Q_INVOKABLE void clearIKJointLimitHistory(); // thread-safe @@ -330,14 +500,16 @@ public: const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; } /**jsdoc + * Gets the avatar orientation. Suitable for use in QML. * @function MyAvatar.setOrientationVar - * @param {object} newOrientationVar + * @param {object} newOrientationVar - The avatar's orientation. */ Q_INVOKABLE void setOrientationVar(const QVariant& newOrientationVar); /**jsdoc + * Gets the avatar orientation. Suitable for use in QML. * @function MyAvatar.getOrientationVar - * @returns {object} + * @returns {object} The avatar's orientation. */ Q_INVOKABLE QVariant getOrientationVar() const; @@ -363,7 +535,7 @@ public: void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); } /**jsdoc - * Get the position in world coordinates of the point directly between your avatar's eyes assuming your avatar was in its + * Gets the position in world coordinates of the point directly between your avatar's eyes assuming your avatar was in its * default pose. This is a reference position; it does not change as your avatar's head moves relative to the avatar * position. * @function MyAvatar.getDefaultEyePosition @@ -377,17 +549,18 @@ public: float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); } /**jsdoc - * The avatar animation system includes a set of default animations along with rules for how those animations are blended - * together with procedural data (such as look at vectors, hand sensors etc.). overrideAnimation() is used to completely - * override all motion from the default animation system (including inverse kinematics for hand and head controllers) and - * play a set of specified animations. To end these animations and restore the default animations, use - * {@link MyAvatar.restoreAnimation}.The avatar animation system includes a set of default animations along with rules for how those animations are blended
+ * together with procedural data (such as look at vectors, hand sensors etc.). overrideAnimation()
is used to
+ * completely override all motion from the default animation system (including inverse kinematics for hand and head
+ * controllers) and play a set of specified animations. To end these animations and restore the default animations, use
+ * {@link MyAvatar.restoreAnimation}.
Note: When using pre-built animation data, it's critical that the joint orientation of the source animation and target * rig are equivalent, since the animation data applies absolute values onto the joints. If the orientations are different, * the avatar will move in unpredictable ways. For more information about avatar joint orientation standards, see - * Avatar Standards.
+ * Avatar Standards. * @function MyAvatar.overrideAnimation - * @param url {string} The URL to the animation file. Animation files need to be .FBX format, but only need to contain the + * @param url {string} The URL to the animation file. Animation files need to be FBX format, but only need to contain the * avatar skeleton and animation data. * @param fps {number} The frames per second (FPS) rate for the animation playback. 30 FPS is normal speed. * @param loop {boolean} Set to true if the animation should loop. @@ -399,15 +572,18 @@ public: * MyAvatar.overrideAnimation(ANIM_URL, 30, true, 0, 53); * Script.setTimeout(function () { * MyAvatar.restoreAnimation(); + * MyAvatar.clearIKJointLimitHistory(); * }, 3000); */ Q_INVOKABLE void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame); /**jsdoc - * The avatar animation system includes a set of default animations along with rules for how those animations are blended together with - * procedural data (such as look at vectors, hand sensors etc.). Playing your own custom animations will override the default animations. - * restoreAnimation() is used to restore all motion from the default animation system including inverse kinematics for hand and head - * controllers. If you aren't currently playing an override animation, this function will have no effect. + * Restores the default animations. + *The avatar animation system includes a set of default animations along with rules for how those animations are blended
+ * together with procedural data (such as look at vectors, hand sensors etc.). Playing your own custom animations will
+ * override the default animations. restoreAnimation()
is used to restore all motion from the default
+ * animation system including inverse kinematics for hand and head controllers. If you aren't currently playing an override
+ * animation, this function has no effect.
Each avatar has an avatar-animation.json file that defines which animations are used and how they are blended together
+ * with procedural data (such as look at vectors, hand sensors etc.). Each animation specified in the avatar-animation.json
+ * file is known as an animation role. Animation roles map to easily understandable actions that the avatar can perform,
+ * such as "idleStand"
, "idleTalk"
, or "walkFwd"
. getAnimationRoles()
+ * is used get the list of animation roles defined in the avatar-animation.json.
Each avatar has an avatar-animation.json file that defines a set of animation roles. Animation roles map to easily
+ * understandable actions that the avatar can perform, such as "idleStand"
, "idleTalk"
, or
+ * "walkFwd"
. To get the full list of roles, use {@ link MyAvatar.getAnimationRoles}.
+ * For each role, the avatar-animation.json defines when the animation is used, the animation clip (FBX) used, and how
+ * animations are blended together with procedural data (such as look at vectors, hand sensors etc.).
+ * overrideRoleAnimation()
is used to change the animation clip (FBX) associated with a specified animation
+ * role. To end the role animation and restore the default, use {@link MyAvatar.restoreRoleAnimation}.
Note: Hand roles only affect the hand. Other 'main' roles, like 'idleStand', 'idleTalk', 'takeoffStand' are full body.
*Note: When using pre-built animation data, it's critical that the joint orientation of the source animation and target * rig are equivalent, since the animation data applies absolute values onto the joints. If the orientations are different, * the avatar will move in unpredictable ways. For more information about avatar joint orientation standards, see - * Avatar Standards. + * Avatar Standards. * @function MyAvatar.overrideRoleAnimation * @param role {string} The animation role to override - * @param url {string} The URL to the animation file. Animation files need to be .FBX format, but only need to contain the avatar skeleton and animation data. + * @param url {string} The URL to the animation file. Animation files need to be in FBX format, but only need to contain the avatar skeleton and animation data. * @param fps {number} The frames per second (FPS) rate for the animation playback. 30 FPS is normal speed. * @param loop {boolean} Set to true if the animation should loop * @param firstFrame {number} The frame the animation should start at @@ -470,13 +650,15 @@ public: Q_INVOKABLE void overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame); /**jsdoc - * Each avatar has an avatar-animation.json file that defines a set of animation roles. Animation roles map to easily understandable actions that - * the avatar can perform, such as "idleStand", "idleTalk", or "walkFwd". To get the full list of roles, use getAnimationRoles(). For each role, - * the avatar-animation.json defines when the animation is used, the animation clip (.FBX) used, and how animations are blended together with - * procedural data (such as look at vectors, hand sensors etc.). You can change the animation clip (.FBX) associated with a specified animation - * role using overrideRoleAnimation(). - * restoreRoleAnimation() is used to restore a specified animation role's default animation clip. If you have not specified an override animation - * for the specified role, this function will have no effect. + * Restores a default role animation. + *
Each avatar has an avatar-animation.json file that defines a set of animation roles. Animation roles map to easily
+ * understandable actions that the avatar can perform, such as "idleStand"
, "idleTalk"
, or
+ * "walkFwd"
. To get the full list of roles, use {@link MyAvatar.getAnimationRoles}. For each role,
+ * the avatar-animation.json defines when the animation is used, the animation clip (FBX) used, and how animations are
+ * blended together with procedural data (such as look-at vectors, hand sensors etc.). You can change the animation clip
+ * (FBX) associated with a specified animation role using {@link MyAvatar.overrideRoleAnimation}.
+ * restoreRoleAnimation()
is used to restore a specified animation role's default animation clip. If you have
+ * not specified an override animation for the specified role, this function has no effect.
* @function MyAvatar.restoreRoleAnimation
* @param role {string} The animation role clip to restore.
*/
@@ -491,90 +673,160 @@ public:
// adding one of the other handlers. While any handler may change a value in animStateDictionaryIn (or supply different values in animStateDictionaryOut)
// a handler must not remove properties from animStateDictionaryIn, nor change property values that it does not intend to change.
// It is not specified in what order multiple handlers are called.
+ /**jsdoc
+ * Adds an animation state handler function that is invoked just before each animation graph update. More than one
+ * animation state handler function may be added by calling addAnimationStateHandler
multiple times. It is not
+ * specified in what order multiple handlers are called.
+ *
The animation state handler function is called with an {@link MyAvatar.AnimStateDictionary|AnimStateDictionary}
+ * "animStateDictionaryIn
" parameter and is expected to return an
+ * {@link MyAvatar.AnimStateDictionary|AnimStateDictionary} "animStateDictionaryOut
" object. The
+ * animStateDictionaryOut
object can be the same object as animStateDictionaryIn
, or it can be a
+ * different object. The animStateDictionaryIn
may be shared among multiple handlers and thus may contain
+ * additional properties specified when adding the different handlers.
A handler may change a value from animStateDictionaryIn
or add different values in the
+ * animStateDictionaryOut
returned. Any property values set in animStateDictionaryOut
will
+ * override those of the internal animation machinery.|null} propertiesList - The list of {@link MyAvatar.AnimStateDictionary|AnimStateDictionary}
+ * properties that should be included in the parameter that the handler function is called with. If null
+ * then all properties are included in the call parameter.
+ * @returns {number} The ID of the animation state handler function if successfully added, undefined
if not.
+ * @example
true
if you do snap turns in HMD mode; false
if you do smooth turns in HMD
+ * mode.
*/
Q_INVOKABLE bool getSnapTurn() const { return _useSnapTurn; }
/**jsdoc
+ * Sets whether your should do snap turns or smooth turns in HMD mode.
* @function MyAvatar.setSnapTurn
- * @param {boolean} on
+ * @param {boolean} on - true
to do snap turns in HMD mode; false
to do smooth turns in HMD mode.
*/
Q_INVOKABLE void setSnapTurn(bool on) { _useSnapTurn = on; }
/**jsdoc
+ * Sets the avatar's dominant hand.
* @function MyAvatar.setDominantHand
- * @param {string} hand
+ * @param {string} hand - The dominant hand: "left"
for the left hand or "right"
for the right
+ * hand. Any other value has no effect.
*/
Q_INVOKABLE void setDominantHand(const QString& hand);
+
/**jsdoc
+ * Gets the avatar's dominant hand.
* @function MyAvatar.getDominantHand
- * @returns {string}
+ * @returns {string} "left"
for the left hand, "right"
for the right hand.
*/
Q_INVOKABLE QString getDominantHand() const;
/**jsdoc
* @function MyAvatar.setHmdAvatarAlignmentType
- * @param {string} hand
+ * @param {string} type - "head"
to align your head and your avatar's head, "eyes"
to align your
+ * eyes and your avatar's eyes.
+ *
*/
- Q_INVOKABLE void setHmdAvatarAlignmentType(const QString& hand);
+ Q_INVOKABLE void setHmdAvatarAlignmentType(const QString& type);
+
/**jsdoc
- * @function MyAvatar.setHmdAvatarAlignmentType
- * @returns {string}
+ * Gets the HMD alignment for your avatar.
+ * @function MyAvatar.getHmdAvatarAlignmentType
+ * @returns {string} "head"
if aligning your head and your avatar's head, "eyes"
if aligning your
+ * eyes and your avatar's eyes.
*/
Q_INVOKABLE QString getHmdAvatarAlignmentType() const;
/**jsdoc
- * @function MyAvatar.setCenterOfGravityModelEnabled
- * @param {boolean} enabled
- */
+ * Sets whether the avatar's hips are balanced over the feet or positioned under the head.
+ * @function MyAvatar.setCenterOfGravityModelEnabled
+ * @param {boolean} enabled - true
to balance the hips over the feet, false
to position the hips
+ * under the head.
+ */
Q_INVOKABLE void setCenterOfGravityModelEnabled(bool value) { _centerOfGravityModelEnabled = value; }
+
/**jsdoc
- * @function MyAvatar.getCenterOfGravityModelEnabled
- * @returns {boolean}
- */
+ * Gets whether the avatar hips are being balanced over the feet or placed under the head.
+ * @function MyAvatar.getCenterOfGravityModelEnabled
+ * @returns {boolean} true
if the hips are being balanced over the feet, false
if the hips are
+ * being positioned under the head.
+ */
Q_INVOKABLE bool getCenterOfGravityModelEnabled() const { return _centerOfGravityModelEnabled; }
+
/**jsdoc
+ * Sets whether the avatar's position updates to recenter the avatar under the head. In room-scale VR, recentering
+ * causes your avatar to follow your HMD as you walk around the room. Disabling recentering is useful if you want to pin
+ * the avatar to a fixed position.
* @function MyAvatar.setHMDLeanRecenterEnabled
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to recenter the avatar under the head as it moves, false
to
+ * disable recentering.
*/
Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; }
+
/**jsdoc
+ * Gets whether the avatar's position updates to recenter the avatar under the head. In room-scale VR, recentering
+ * causes your avatar to follow your HMD as you walk around the room.
* @function MyAvatar.getHMDLeanRecenterEnabled
- * @returns {boolean}
+ * @returns {boolean} true
if recentering is enabled, false
if not.
*/
Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; }
+
/**jsdoc
- * Request to enable hand touch effect globally
+ * Requests that the hand touch effect is disabled for your avatar. Any resulting change in the status of the hand touch
+ * effect will be signaled by {@link MyAvatar.shouldDisableHandTouchChanged}.
+ * The hand touch effect makes the avatar's fingers adapt to the shape of any object grabbed, creating the effect that + * it is really touching that object.
* @function MyAvatar.requestEnableHandTouch */ Q_INVOKABLE void requestEnableHandTouch(); + /**jsdoc - * Request to disable hand touch effect globally + * Requests that the hand touch effect is enabled for your avatar. Any resulting change in the status of the hand touch + * effect will be signaled by {@link MyAvatar.shouldDisableHandTouchChanged}. + *The hand touch effect makes the avatar's fingers adapt to the shape of any object grabbed, creating the effect that + * it is really touching that object.
* @function MyAvatar.requestDisableHandTouch */ Q_INVOKABLE void requestDisableHandTouch(); + /**jsdoc - * Disables hand touch effect on a specific entity + * Disables the hand touch effect on a specific entity. + *The hand touch effect makes the avatar's fingers adapt to the shape of any object grabbed, creating the effect that + * it is really touching that object.
* @function MyAvatar.disableHandTouchForID - * @param {Uuid} entityID - ID of the entity that will disable hand touch effect + * @param {Uuid} entityID - The entity that the hand touch effect will be disabled for. */ Q_INVOKABLE void disableHandTouchForID(const QUuid& entityID); + /**jsdoc - * Enables hand touch effect on a specific entity + * Enables the hand touch effect on a specific entity. + *The hand touch effect makes the avatar's fingers adapt to the shape of any object grabbed, creating the effect that + * it is really touching that object.
* @function MyAvatar.enableHandTouchForID - * @param {Uuid} entityID - ID of the entity that will enable hand touch effect + * @param {Uuid} entityID - The entity that the hand touch effect will be enabled for. */ Q_INVOKABLE void enableHandTouchForID(const QUuid& entityID); @@ -612,29 +864,43 @@ public: float getDriveKey(DriveKeys key) const; /**jsdoc + * Gets the value of a drive key, regardless of whether it is disabled. * @function MyAvatar.getRawDriveKey - * @param {DriveKeys} key - * @returns {number} + * @param {MyAvatar.DriveKeys} key - The drive key. + * @returns {number} The value of the drive key. */ Q_INVOKABLE float getRawDriveKey(DriveKeys key) const; void relayDriveKeysToCharacterController(); /**jsdoc + * Disables the action associated with a drive key. * @function MyAvatar.disableDriveKey - * @param {DriveKeys} key + * @param {MyAvatar.DriveKeys} key - The drive key to disable. + * @exampletrue
if the drive key is disabled, false
if it isn't.
*/
Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const;
@@ -649,7 +915,7 @@ public:
/**jsdoc
* Recenter the avatar in the horizontal direction, if {@link MyAvatar|MyAvatar.hmdLeanRecenterEnabled}
is
* false
.
- * @ function MyAvatar.triggerHorizontalRecenter
+ * @function MyAvatar.triggerHorizontalRecenter
*/
Q_INVOKABLE void triggerHorizontalRecenter();
@@ -660,10 +926,10 @@ public:
Q_INVOKABLE void triggerRotationRecenter();
/**jsdoc
- *The isRecenteringHorizontally function returns true if MyAvatar
- *is translating the root of the Avatar to keep the center of gravity under the head.
- *isActive(Horizontal) is returned.
- *@function MyAvatar.isRecenteringHorizontally
+ * Gets whether the avatar is configured to keep its center of gravity under its head.
+ * @function MyAvatar.isRecenteringHorizontally
+ * @returns {boolean} true
if the avatar is keeping its center of gravity under its head position,
+ * false
if not.
*/
Q_INVOKABLE bool isRecenteringHorizontally() const;
@@ -672,7 +938,7 @@ public:
const MyHead* getMyHead() const;
/**jsdoc
- * Get the current position of the avatar's "Head" joint.
+ * Gets the current position of the avatar's "Head" joint.
* @function MyAvatar.getHeadPosition
* @returns {Vec3} The current position of the avatar's "Head" joint.
* @example 0
, in degrees.
*/
Q_INVOKABLE float getHeadDeltaPitch() const { return getHead()->getDeltaPitch(); }
/**jsdoc
- * Get the current position of the point directly between the avatar's eyes.
+ * Gets the current position of the point directly between the avatar's eyes.
* @function MyAvatar.getEyePosition
* @returns {Vec3} The current position of the point directly between the avatar's eyes.
* @example Note: The Leap Motion isn't part of the hand controller input system. (Instead, it manipulates the avatar's joints * for hand animation.)
* @function MyAvatar.getLeftHandPosition @@ -742,7 +1021,8 @@ public: Q_INVOKABLE glm::vec3 getLeftHandPosition() const; /**jsdoc - * Get the position of the avatar's right hand as positioned by a hand controller (e.g., Oculus Touch or Vive).Note: The Leap Motion isn't part of the hand controller input system. (Instead, it manipulates the avatar's joints * for hand animation.)
* @function MyAvatar.getRightHandPosition @@ -754,53 +1034,71 @@ public: Q_INVOKABLE glm::vec3 getRightHandPosition() const; /**jsdoc + * Gets the position 0.3m in front of the left hand's position in the direction along the palm, in avatar coordinates, as + * positioned by a hand controller. * @function MyAvatar.getLeftHandTipPosition - * @returns {Vec3} + * @returns {Vec3} The position 0.3m in front of the left hand's position in the direction along the palm, in avatar + * coordinates. If the hand isn't being positioned by a controller,{@link Vec3(0)|Vec3.ZERO}
is returned.
*/
Q_INVOKABLE glm::vec3 getLeftHandTipPosition() const;
/**jsdoc
+ * Gets the position 0.3m in front of the right hand's position in the direction along the palm, in avatar coordinates, as
+ * positioned by a hand controller.
* @function MyAvatar.getRightHandTipPosition
- * @returns {Vec3}
+ * @returns {Vec3} The position 0.3m in front of the right hand's position in the direction along the palm, in avatar
+ * coordinates. If the hand isn't being positioned by a controller, {@link Vec3(0)|Vec3.ZERO}
is returned.
*/
Q_INVOKABLE glm::vec3 getRightHandTipPosition() const;
/**jsdoc
- * Get the pose (position, rotation, velocity, and angular velocity) of the avatar's left hand as positioned by a
- * hand controller (e.g., Oculus Touch or Vive).Note: The Leap Motion isn't part of the hand controller input system. (Instead, it manipulates the avatar's joints
* for hand animation.) If you are using the Leap Motion, the return value's valid
property will be
* false
and any pose values returned will not be meaningful.
Note: The Leap Motion isn't part of the hand controller input system. (Instead, it manipulates the avatar's joints
* for hand animation.) If you are using the Leap Motion, the return value's valid
property will be
* false
and any pose values returned will not be meaningful.
Note: Leap Motion isn't part of the hand controller input system. (Instead, it manipulates the avatar's joints
+ * for hand animation.) If you are using Leap Motion, the return value's valid
property will be
+ * false
and any pose values returned will not be meaningful.
Note: Leap Motion isn't part of the hand controller input system. (Instead, it manipulates the avatar's joints
+ * for hand animation.) If you are using Leap Motion, the return value's valid
property will be
+ * false
and any pose values returned will not be meaningful.
Note: Only works on the hips joint.
* @function MyAvatar.pinJoint - * @param {number} index - * @param {Vec3} position - * @param {Quat} orientation - * @returns {boolean} + * @param {number} index - The index of the joint. + * @param {Vec3} position - The position of the joint in world coordinates. + * @param {Quat} orientation - The orientation of the joint in world coordinates. + * @returns {boolean}true
if the joint was pinned, false
if it wasn't.
*/
Q_INVOKABLE bool pinJoint(int index, const glm::vec3& position, const glm::quat& orientation);
bool isJointPinned(int index);
/**jsdoc
+ * Clears a lock on a joint's position and orientation, as set by {@link MyAvatar.pinJoint|pinJoint}.
+ * Note: Only works on the hips joint.
* @function MyAvatar.clearPinOnJoint - * @param {number} index - * @returns {boolean} + * @param {number} index - The index of the joint. + * @returns {boolean}true
if the joint was unpinned, false
if it wasn't.
*/
Q_INVOKABLE bool clearPinOnJoint(int index);
/**jsdoc
+ * Gets the maximum error distance from the most recent inverse kinematics (IK) solution.
* @function MyAvatar.getIKErrorOnLastSolve
- * @returns {number}
+ * @returns {number} The maximum IK error distance.
*/
Q_INVOKABLE float getIKErrorOnLastSolve() const;
/**jsdoc
+ * Changes the user's avatar and associated descriptive name.
* @function MyAvatar.useFullAvatarURL
- * @param {string} fullAvatarURL
- * @param {string} [modelName=""]
+ * @param {string} fullAvatarURL - The URL of the avatar's .fst
file.
+ * @param {string} [modelName=""] - Descriptive name of the avatar.
*/
Q_INVOKABLE void useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName = QString());
/**jsdoc
- * Get the complete URL for the current avatar.
+ * Gets the complete URL for the current avatar.
* @function MyAvatar.getFullAvatarURLFromPreferences
* @returns {string} The full avatar model name.
* @example true
if your avatar is flying and not taking off or falling, otherwise
- * false
.
+ * @returns {boolean} true
if your avatar is flying and not taking off or falling, false
if not.
*/
Q_INVOKABLE bool isFlying();
/**jsdoc
- * Check whether your avatar is in the air or not.
+ * Checks whether your avatar is in the air.
* @function MyAvatar.isInAir
* @returns {boolean} true
if your avatar is taking off, flying, or falling, otherwise false
* because your avatar is on the ground.
@@ -959,7 +1263,7 @@ public:
Q_INVOKABLE bool isInAir();
/**jsdoc
- * Set your preference for flying in your current desktop or HMD display mode. Note that your ability to fly also depends
+ * Sets your preference for flying in your current desktop or HMD display mode. Note that your ability to fly also depends
* on whether the domain you're in allows you to fly.
* @function MyAvatar.setFlyingEnabled
* @param {boolean} enabled - Set true
if you want to enable flying in your current desktop or HMD display
@@ -968,7 +1272,7 @@ public:
Q_INVOKABLE void setFlyingEnabled(bool enabled);
/**jsdoc
- * Get your preference for flying in your current desktop or HMD display mode. Note that your ability to fly also depends
+ * Gets your preference for flying in your current desktop or HMD display mode. Note that your ability to fly also depends
* on whether the domain you're in allows you to fly.
* @function MyAvatar.getFlyingEnabled
* @returns {boolean} true
if your preference is to enable flying in your current desktop or HMD display mode,
@@ -977,7 +1281,7 @@ public:
Q_INVOKABLE bool getFlyingEnabled();
/**jsdoc
- * Set your preference for flying in desktop display mode. Note that your ability to fly also depends on whether the domain
+ * Sets your preference for flying in desktop display mode. Note that your ability to fly also depends on whether the domain
* you're in allows you to fly.
* @function MyAvatar.setFlyingDesktopPref
* @param {boolean} enabled - Set true
if you want to enable flying in desktop display mode, otherwise set
@@ -986,7 +1290,7 @@ public:
Q_INVOKABLE void setFlyingDesktopPref(bool enabled);
/**jsdoc
- * Get your preference for flying in desktop display mode. Note that your ability to fly also depends on whether the domain
+ * Gets your preference for flying in desktop display mode. Note that your ability to fly also depends on whether the domain
* you're in allows you to fly.
* @function MyAvatar.getFlyingDesktopPref
* @returns {boolean} true
if your preference is to enable flying in desktop display mode, otherwise
@@ -995,7 +1299,7 @@ public:
Q_INVOKABLE bool getFlyingDesktopPref();
/**jsdoc
- * Set your preference for flying in HMD display mode. Note that your ability to fly also depends on whether the domain
+ * Sets your preference for flying in HMD display mode. Note that your ability to fly also depends on whether the domain
* you're in allows you to fly.
* @function MyAvatar.setFlyingHMDPref
* @param {boolean} enabled - Set true
if you want to enable flying in HMD display mode, otherwise set
@@ -1004,7 +1308,7 @@ public:
Q_INVOKABLE void setFlyingHMDPref(bool enabled);
/**jsdoc
- * Get your preference for flying in HMD display mode. Note that your ability to fly also depends on whether the domain
+ * Gets your preference for flying in HMD display mode. Note that your ability to fly also depends on whether the domain
* you're in allows you to fly.
* @function MyAvatar.getFlyingHMDPref
* @returns {boolean} true
if your preference is to enable flying in HMD display mode, otherwise
@@ -1012,65 +1316,104 @@ public:
*/
Q_INVOKABLE bool getFlyingHMDPref();
-
/**jsdoc
+ * Gets the target scale of the avatar. The target scale is the desired scale of the avatar without any restrictions on
+ * permissible scale values imposed by the domain.
* @function MyAvatar.getAvatarScale
- * @returns {number}
+ * @returns {number} The target scale for the avatar, range 0.005
– 1000.0
.
*/
Q_INVOKABLE float getAvatarScale();
/**jsdoc
+ * Sets the target scale of the avatar. The target scale is the desired scale of the avatar without any restrictions on
+ * permissible scale values imposed by the domain.
* @function MyAvatar.setAvatarScale
- * @param {number} scale
+ * @param {number} scale - The target scale for the avatar, range 0.005
– 1000.0
.
*/
Q_INVOKABLE void setAvatarScale(float scale);
-
/**jsdoc
+ * Sets whether the avatar should collide with entities.
+ * Note: A false
value won't disable collisions if the avatar is in a zone that disallows
+ * collisionless avatars. However, the false
value will be set so that collisions are disabled as soon as the
+ * avatar moves to a position where collisionless avatars are allowed.
* @function MyAvatar.setCollisionsEnabled
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to enable the avatar to collide with entities, false
to
+ * disable.
*/
Q_INVOKABLE void setCollisionsEnabled(bool enabled);
/**jsdoc
+ * Gets whether the avatar will currently collide with entities.
+ *
Note: The avatar will always collide with entities if in a zone that disallows collisionless avatars.
* @function MyAvatar.getCollisionsEnabled
- * @returns {boolean}
+ * @returns {boolean} true
if the avatar will currently collide with entities, false
if it won't.
*/
Q_INVOKABLE bool getCollisionsEnabled();
/**jsdoc
- * @function MyAvatar.setOtherAvatarsCollisionsEnabled
- * @param {boolean} enabled
- */
+ * Sets whether the avatar should collide with other avatars.
+ * @function MyAvatar.setOtherAvatarsCollisionsEnabled
+ * @param {boolean} enabled - true
to enable the avatar to collide with other avatars, false
+ * to disable.
+ */
Q_INVOKABLE void setOtherAvatarsCollisionsEnabled(bool enabled);
/**jsdoc
- * @function MyAvatar.getOtherAvatarsCollisionsEnabled
- * @returns {boolean}
- */
+ * Gets whether the avatar will collide with other avatars.
+ * @function MyAvatar.getOtherAvatarsCollisionsEnabled
+ * @returns {boolean} true
if the avatar will collide with other avatars, false
if it won't.
+ */
Q_INVOKABLE bool getOtherAvatarsCollisionsEnabled();
/**jsdoc
- * @function MyAvatar.getCollisionCapsule
- * @returns {object}
- */
+ * Gets the avatar's collision capsule: a cylinder with hemispherical ends that approximates the extents or the avatar.
+ *
Warning: The values returned are in world coordinates but aren't necessarily up to date with the + * avatar's current position.
+ * @function MyAvatar.getCollisionCapsule + * @returns {MyAvatar.CollisionCapsule} The avatar's collision capsule. + */ Q_INVOKABLE QVariantMap getCollisionCapsule() const; /**jsdoc * @function MyAvatar.setCharacterControllerEnabled - * @param {boolean} enabled - * @deprecated + * @param {boolean} enabled -true
to enable the avatar to collide with entities, false
to
+ * disable.
+ * @deprecated Use {@link MyAvatar.setCollisionsEnabled} instead.
*/
Q_INVOKABLE void setCharacterControllerEnabled(bool enabled); // deprecated
/**jsdoc
* @function MyAvatar.getCharacterControllerEnabled
- * @returns {boolean}
- * @deprecated
+ * @returns {boolean} true
if the avatar will currently collide with entities, false
if it won't.
+ * @deprecated Use {@link MyAvatar.getCollisionsEnabled} instead.
*/
Q_INVOKABLE bool getCharacterControllerEnabled(); // deprecated
+ /**jsdoc
+ * @comment Different behavior to the Avatar version of this method.
+ * Gets the rotation of a joint relative to the avatar.
+ * @function MyAvatar.getAbsoluteJointRotationInObjectFrame
+ * @param {number} index - The index of the joint.
+ * @returns {Quat} The rotation of the joint relative to the avatar.
+ * @example > 0
).
* @function MyAvatar.isUp
- * @param {Vec3} direction
- * @returns {boolean}
+ * @param {Vec3} direction - The vector to test.
+ * @returns {boolean} true
if the direction vector is pointing generally in the direction of the avatar's "up"
+ * direction.
*/
Q_INVOKABLE bool isUp(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) > 0.0f; }; // true iff direction points up wrt avatar's definition of up.
/**jsdoc
+ * Tests whether a vector is pointing in the general direction of the avatar's "down" direction (i.e., dot product of
+ * vectors is < 0
).
* @function MyAvatar.isDown
- * @param {Vec3} direction
- * @returns {boolean}
+ * @param {Vec3} direction - The vector to test.
+ * @returns {boolean} true
if the direction vector is pointing generally in the direction of the avatar's
+ * "down" direction.
*/
Q_INVOKABLE bool isDown(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) < 0.0f; };
@@ -1161,116 +1510,164 @@ public:
void prepareAvatarEntityDataForReload();
/**jsdoc
- * Create a new grab.
+ * Creates a new grab that grabs an entity.
* @function MyAvatar.grab
- * @param {Uuid} targetID - id of grabbed thing
- * @param {number} parentJointIndex - avatar joint being used to grab
- * @param {Vec3} offset - target's positional offset from joint
- * @param {Quat} rotationalOffset - target's rotational offset from joint
- * @returns {Uuid} id of the new grab
+ * @param {Uuid} targetID - The ID of the entity to grab.
+ * @param {number} parentJointIndex - The avatar joint to use to grab the entity.
+ * @param {Vec3} offset - The target's local position relative to the joint.
+ * @param {Quat} rotationalOffset - The target's local rotation relative to the joint.
+ * @returns {Uuid} The ID of the new grab.
+ * @example true
to activate flow simulation.
- * @param {boolean} - Set to true
to activate collisions.
- * @param {Object} physicsConfig - object with the customized physic parameters
- * i.e. {"hair": {"active": true, "stiffness": 0.0, "radius": 0.04, "gravity": -0.035, "damping": 0.8, "inertia": 0.8, "delta": 0.35}}
- * @param {Object} collisionsConfig - object with the customized collision parameters
- * i.e. {"Spine2": {"type": "sphere", "radius": 0.14, "offset": {"x": 0.0, "y": 0.2, "z": 0.0}}}
- */
+ * Enables and disables flow simulation of physics on the avatar's hair, clothes, and body parts. See
+ * {@link https://docs.highfidelity.com/create/avatars/add-flow.html|Add Flow to Your Avatar} for more
+ * information.
+ * @function MyAvatar.useFlow
+ * @param {boolean} isActive - true
if flow simulation is enabled on the joint, false
if it isn't.
+ * @param {boolean} isCollidable - true
to enable collisions in the flow simulation, false
to
+ * disable.
+ * @param {Object1000
.
+ * Increases the avatar's scale by five percent, up to a minimum scale of 1000
.
* @function MyAvatar.increaseSize
* @example 0.25
.
+ * Decreases the avatar's scale by five percent, down to a minimum scale of 0.25
.
* @function MyAvatar.decreaseSize
* @example 1.0
.
+ * Resets the avatar's scale back to the default scale of 1.0
.
* @function MyAvatar.resetSize
*/
void resetSize();
/**jsdoc
* @function MyAvatar.animGraphLoaded
+ * @deprecated This function is deprecated and will be removed.
*/
void animGraphLoaded();
/**jsdoc
+ * Sets the amount of gravity applied to the avatar in the y-axis direction. (Negative values are downward.)
* @function MyAvatar.setGravity
- * @param {number} gravity
+ * @param {number} gravity - The amount of gravity to be applied to the avatar, in m/s2.
*/
void setGravity(float gravity);
/**jsdoc
+ * Sets the amount of gravity applied to the avatar in the y-axis direction. (Negative values are downward.) The default
+ * value is -5
m/s2.
* @function MyAvatar.getGravity
- * @returns {number}
+ * @returns {number} The amount of gravity currently applied to the avatar, in m/s2.
*/
float getGravity();
/**jsdoc
- * Move the avatar to a new position and/or orientation in the domain, while taking into account Avatar leg-length.
+ * Moves the avatar to a new position and/or orientation in the domain, while taking into account Avatar leg-length.
* @function MyAvatar.goToFeetLocation
* @param {Vec3} position - The new position for the avatar, in world coordinates.
* @param {boolean} [hasOrientation=false] - Set to true
to set the orientation of the avatar.
@@ -1278,13 +1675,12 @@ public slots:
* @param {boolean} [shouldFaceLocation=false] - Set to true
to position the avatar a short distance away from
* the new position and orientate the avatar to face the position.
*/
-
void goToFeetLocation(const glm::vec3& newPosition,
bool hasOrientation, const glm::quat& newOrientation,
bool shouldFaceLocation);
/**jsdoc
- * Move the avatar to a new position and/or orientation in the domain.
+ * Moves the avatar to a new position and/or orientation in the domain.
* @function MyAvatar.goToLocation
* @param {Vec3} position - The new position for the avatar, in world coordinates.
* @param {boolean} [hasOrientation=false] - Set to true
to set the orientation of the avatar.
@@ -1297,133 +1693,183 @@ public slots:
bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(),
bool shouldFaceLocation = false, bool withSafeLanding = true);
/**jsdoc
+ * Moves the avatar to a new position and (optional) orientation in the domain.
* @function MyAvatar.goToLocation
- * @param {object} properties
+ * @param {MyAvatar.GoToProperties} target - The goto target.
*/
void goToLocation(const QVariant& properties);
/**jsdoc
+ * Moves the avatar to a new position and then enables collisions.
* @function MyAvatar.goToLocationAndEnableCollisions
- * @param {Vec3} position
+ * @param {Vec3} position - The new position for the avatar, in world coordinates.
*/
void goToLocationAndEnableCollisions(const glm::vec3& newPosition);
/**jsdoc
* @function MyAvatar.safeLanding
- * @param {Vec3} position
- * @returns {boolean}
+ * @param {Vec3} position -The new position for the avatar, in world coordinates.
+ * @returns {boolean} true
if the avatar was moved, false
if it wasn't.
+ * @deprecated This function is deprecated and will be removed.
*/
bool safeLanding(const glm::vec3& position);
/**jsdoc
* @function MyAvatar.restrictScaleFromDomainSettings
- * @param {objecct} domainSettingsObject
+ * @param {object} domainSettings - Domain settings.
+ * @deprecated This function is deprecated and will be removed.
*/
void restrictScaleFromDomainSettings(const QJsonObject& domainSettingsObject);
/**jsdoc
* @function MyAvatar.clearScaleRestriction
+ * @deprecated This function is deprecated and will be removed from the API.
*/
void clearScaleRestriction();
/**jsdoc
+ * Adds a thrust to your avatar's current thrust to be applied for a short while.
* @function MyAvatar.addThrust
- * @param {Vec3} thrust
+ * @param {Vec3} thrust - The thrust direction and magnitude.
+ * @deprecated Use {@link MyAvatar|MyAvatar.motorVelocity} and related properties instead.
*/
// Set/Get update the thrust that will move the avatar around
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
/**jsdoc
+ * Gets the thrust currently being applied to your avatar.
* @function MyAvatar.getThrust
- * @returns {vec3}
+ * @returns {Vec3} The thrust currently being applied to your avatar.
+ * @deprecated Use {@link MyAvatar|MyAvatar.motorVelocity} and related properties instead.
*/
glm::vec3 getThrust() { return _thrust; };
/**jsdoc
+ * Sets the thrust to be applied to your avatar for a short while.
* @function MyAvatar.setThrust
- * @param {Vec3} thrust
+ * @param {Vec3} thrust - The thrust direction and magnitude.
+ * @deprecated Use {@link MyAvatar|MyAvatar.motorVelocity} and related properties instead.
*/
void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }
/**jsdoc
+ * Updates avatar motion behavior from the Developer > Avatar > Enable Default Motor Control and Enable Scripted
+ * Motor Control menu items.
* @function MyAvatar.updateMotionBehaviorFromMenu
*/
Q_INVOKABLE void updateMotionBehaviorFromMenu();
/**jsdoc
- * @function MyAvatar.setToggleHips
- * @param {boolean} enabled
- */
+ * @function MyAvatar.setToggleHips
+ * @param {boolean} enabled - Enabled.
+ * @deprecated This function is deprecated and will be removed.
+ */
void setToggleHips(bool followHead);
+
/**jsdoc
- * @function MyAvatar.setEnableDebugDrawBaseOfSupport
- * @param {boolean} enabled
- */
+ * Displays the base of support area debug graphics if in HMD mode. If your head goes outside this area your avatar's hips
+ * are moved to counterbalance your avatar, and if your head moves too far then your avatar's position is moved (i.e., a
+ * step happens).
+ * @function MyAvatar.setEnableDebugDrawBaseOfSupport
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
+ */
void setEnableDebugDrawBaseOfSupport(bool isEnabled);
+
/**jsdoc
+ * Displays default pose debug graphics.
* @function MyAvatar.setEnableDebugDrawDefaultPose
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawDefaultPose(bool isEnabled);
+
/**jsdoc
+ * Displays animation debug graphics.
* @function MyAvatar.setEnableDebugDrawAnimPose
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawAnimPose(bool isEnabled);
+
/**jsdoc
+ * Displays position debug graphics.
* @function MyAvatar.setEnableDebugDrawPosition
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawPosition(bool isEnabled);
+
/**jsdoc
+ * Displays controller hand target debug graphics.
* @function MyAvatar.setEnableDebugDrawHandControllers
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawHandControllers(bool isEnabled);
+
/**jsdoc
+ * Displays sensor-to-world matrix debug graphics.
* @function MyAvatar.setEnableDebugDrawSensorToWorldMatrix
- * @param {boolean} enabled
+ * @param {boolean} enable - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawSensorToWorldMatrix(bool isEnabled);
+
/**jsdoc
+ * Displays inverse kinematics targets debug graphics.
* @function MyAvatar.setEnableDebugDrawIKTargets
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawIKTargets(bool isEnabled);
+
/**jsdoc
+ * Displays inverse kinematics constraints debug graphics.
* @function MyAvatar.setEnableDebugDrawIKConstraints
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawIKConstraints(bool isEnabled);
+
/**jsdoc
+ * Displays inverse kinematics chains debug graphics.
* @function MyAvatar.setEnableDebugDrawIKChains
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawIKChains(bool isEnabled);
+
/**jsdoc
+ * Displays detailed collision debug graphics.
* @function MyAvatar.setEnableDebugDrawDetailedCollision
- * @param {boolean} enabled
+ * @param {boolean} enabled - true
to show the debug graphics, false
to hide.
*/
void setEnableDebugDrawDetailedCollision(bool isEnabled);
/**jsdoc
- * Get whether or not your avatar mesh is visible.
+ * Gets whether your avatar mesh is visible.
* @function MyAvatar.getEnableMeshVisible
* @returns {boolean} true
if your avatar's mesh is visible, otherwise false
.
*/
bool getEnableMeshVisible() const override;
+ /**jsdoc
+ * @function MyAvatar.storeAvatarEntityDataPayload
+ * @deprecated This function is deprecated and will be removed.
+ */
void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload) override;
+
+ /**jsdoc
+ * @comment Uses the base class's JSDoc.
+ */
void clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree = true) override;
+
+ /**jsdoc
+ * @function MyAvatar.sanitizeAvatarEntityProperties
+ * @param {EntityItemProperties} properties - Properties.
+ * @deprecated This function is deprecated and will be removed.
+ */
void sanitizeAvatarEntityProperties(EntityItemProperties& properties) const;
/**jsdoc
- * Set whether or not your avatar mesh is visible.
+ * Sets whether your avatar mesh is visible to you.
* @function MyAvatar.setEnableMeshVisible
- * @param {boolean} visible - true
to set your avatar mesh visible; false
to set it invisible.
+ * @param {boolean} enabled - true
to show your avatar mesh, false
to hide.
* @example true
to enable IK, false
to disable.
*/
void setEnableInverseKinematics(bool isEnabled);
/**jsdoc
+ * Gets the URL of the override animation graph.
+ * See {@link https://docs.highfidelity.com/create/avatars/custom-animations.html|Custom Avatar Animations} for + * information on animation graphs.
* @function MyAvatar.getAnimGraphOverrideUrl - * @returns {string} + * @returns {string} The URL of the override animation graph JSON file.""
if there is no override animation
+ * graph.
*/
QUrl getAnimGraphOverrideUrl() const; // thread-safe
/**jsdoc
+ * Sets the animation graph to use in preference to the default animation graph.
+ * See {@link https://docs.highfidelity.com/create/avatars/custom-animations.html|Custom Avatar Animations} for + * information on animation graphs.
* @function MyAvatar.setAnimGraphOverrideUrl - * @param {string} url + * @param {string} url - The URL of the animation graph JSON file to use. Set to""
to clear an override.
*/
void setAnimGraphOverrideUrl(QUrl value); // thread-safe
/**jsdoc
+ * Gets the URL of animation graph (i.e., the avatar animation JSON) that's currently being used for avatar animations.
+ * See {@link https://docs.highfidelity.com/create/avatars/custom-animations.html|Custom Avatar Animations} for + * information on animation graphs.
* @function MyAvatar.getAnimGraphUrl - * @returns {string} + * @returns {string} The URL of the current animation graph JSON file. + * @ExampleSee {@link https://docs.highfidelity.com/create/avatars/custom-animations.html|Custom Avatar Animations} for + * information on animation graphs.
* @function MyAvatar.setAnimGraphUrl - * @param {string} url + * @param {string} url - The URL of the animation graph JSON file to use. */ void setAnimGraphUrl(const QUrl& url); // thread-safe /**jsdoc + * Gets your listening position for spatialized audio. The position depends on the value of the + * {@link Myavatar|audioListenerMode} property. * @function MyAvatar.getPositionForAudio - * @returns {Vec3} + * @returns {Vec3} Your listening position. */ glm::vec3 getPositionForAudio(); /**jsdoc + * Gets the orientation of your listening position for spatialized audio. The orientation depends on the value of the + * {@link Myavatar|audioListenerMode} property. * @function MyAvatar.getOrientationForAudio - * @returns {Quat} + * @returns {Quat} The orientation of your listening position. */ glm::quat getOrientationForAudio(); /**jsdoc * @function MyAvatar.setModelScale - * @param {number} scale + * @param {number} scale - The scale. + * @deprecated This function is deprecated and will be removed. */ virtual void setModelScale(float scale) override; signals: /**jsdoc + * Triggered when the {@link MyAvatar|audioListenerMode} property value changes. * @function MyAvatar.audioListenerModeChanged * @returns {Signal} */ @@ -1492,12 +1960,14 @@ signals: /**jsdoc * @function MyAvatar.transformChanged * @returns {Signal} + * @deprecated This signal is deprecated and will be removed. */ void transformChanged(); /**jsdoc + * Triggered when the {@link MyAvatar|collisionSoundURL} property value changes. * @function MyAvatar.newCollisionSoundURL - * @param {string} url + * @param {string} url - The URL of the new collision sound. * @returns {Signal} */ void newCollisionSoundURL(const QUrl& url); @@ -1505,7 +1975,7 @@ signals: /**jsdoc * Triggered when the avatar collides with an entity. * @function MyAvatar.collisionWithEntity - * @param {Collision} collision + * @param {Collision} collision - Details of the collision. * @returns {Signal} * @exampletrue
if collisions with the environment are enabled, false
if
+ * they're not.
* @returns {Signal}
*/
void collisionsEnabledChanged(bool enabled);
/**jsdoc
- * Triggered when collisions with other avatars enabled or disabled
- * @function MyAvatar.otherAvatarsCollisionsEnabledChanged
- * @param {boolean} enabled
- * @returns {Signal}
- */
+ * Triggered when collisions with other avatars are enabled or disabled.
+ * @function MyAvatar.otherAvatarsCollisionsEnabledChanged
+ * @param {boolean} enabled - true
if collisions with other avatars are enabled, false
if they're
+ * not.
+ * @returns {Signal}
+ */
void otherAvatarsCollisionsEnabledChanged(bool enabled);
/**jsdoc
- * Triggered when avatar's animation url changes
+ * Triggered when the avatar's animation graph being used changes.
* @function MyAvatar.animGraphUrlChanged
- * @param {url} url
+ * @param {string} url - The URL of the new animation graph JSON file.
* @returns {Signal}
- */
+ * @example Synonym of {@link MyAvatar.skeletonModelURLChanged|skeletonModelURLChanged}.
* @function MyAvatar.skeletonChanged * @returns {Signal} */ void skeletonChanged(); /**jsdoc + * Triggered when the avatar's dominant hand changes. * @function MyAvatar.dominantHandChanged - * @param {string} hand + * @param {string} hand - The dominant hand:"left"
for the left hand, "right"
for the right hand.
* @returns {Signal}
*/
void dominantHandChanged(const QString& hand);
/**jsdoc
+ * Triggered when the HMD alignment for your avatar changes.
* @function MyAvatar.hmdAvatarAlignmentTypeChanged
- * @param {string} type
+ * @param {string} type - "head"
if aligning your head and your avatar's head, "eyes"
if aligning
+ * your eyes and your avatar's eyes.
* @returns {Signal}
*/
void hmdAvatarAlignmentTypeChanged(const QString& type);
/**jsdoc
+ * Triggered when the avatar's sensorToWorldScale
property value changes.
* @function MyAvatar.sensorToWorldScaleChanged
- * @param {number} scale
+ * @param {number} scale - The scale that transforms dimensions in the user's real world to the avatar's size in the virtual
+ * world.
* @returns {Signal}
*/
void sensorToWorldScaleChanged(float sensorToWorldScale);
/**jsdoc
+ * Triggered when the a model is attached to or detached from one of the avatar's joints using one of
+ * {@link MyAvatar.attach|attach}, {@link MyAvatar.detachOne|detachOne}, {@link MyAvatar.detachAll|detachAll}, or
+ * {@link MyAvatar.setAttachmentData|setAttachmentData}.
* @function MyAvatar.attachmentsChanged
* @returns {Signal}
+ * @deprecated Use avatar entities instead.
*/
void attachmentsChanged();
/**jsdoc
+ * Triggered when the avatar's size changes. This can be due to the user changing the size of their avatar or the domain
+ * limiting the size of their avatar.
* @function MyAvatar.scaleChanged
* @returns {Signal}
*/
void scaleChanged();
/**jsdoc
- * Triggered when hand touch is globally enabled or disabled
+ * Triggered when the hand touch effect is enabled or disabled for the avatar.
+ * The hand touch effect makes the avatar's fingers adapt to the shape of any object grabbed, creating the effect that + * it is really touching that object.
* @function MyAvatar.shouldDisableHandTouchChanged - * @param {boolean} shouldDisable + * @param {boolean} disabled -true
if the hand touch effect is disabled for the avatar,
+ * false
if it isn't disabled.
* @returns {Signal}
*/
void shouldDisableHandTouchChanged(bool shouldDisable);
/**jsdoc
- * Triggered when hand touch is enabled or disabled for an specific entity
+ * Triggered when the hand touch is enabled or disabled on a specific entity.
+ * The hand touch effect makes the avatar's fingers adapt to the shape of any object grabbed, creating the effect that + * it is really touching that object.
* @function MyAvatar.disableHandTouchForIDChanged - * @param {Uuid} entityID - ID of the entity that will enable hand touch effect - * @param {boolean} disable + * @param {Uuid} entityID - The entity that the hand touch effect has been enabled or disabled for. + * @param {boolean} disabled -true
if the hand touch effect is disabled for the entity,
+ * false
if it isn't disabled.
* @returns {Signal}
*/
void disableHandTouchForIDChanged(const QUuid& entityID, bool disable);
diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp
index bf43db3044..4f2171d451 100644
--- a/interface/src/scripting/Audio.cpp
+++ b/interface/src/scripting/Audio.cpp
@@ -228,6 +228,9 @@ void Audio::loadData() {
_hmdMuted = _hmdMutedSetting.get();
_pttDesktop = _pttDesktopSetting.get();
_pttHMD = _pttHMDSetting.get();
+
+ auto client = DependencyManager::getparentID
is an avatar skeleton. A value of 65535
means "no joint".
*
- * @property {boolean} isFacingAvatar - If true< / code>, the overlay is rotated to face the user's camera about an axis
+ * @property {boolean} isFacingAvatar - If true
, the overlay is rotated to face the user's camera about an axis
* parallel to the user's avatar's "up" direction.
- * @property {string} text="" - The text to display.Text does not automatically wrap; use \n< / code> for a line break.
+ * @property {string} text="" - The text to display.Text does not automatically wrap; use \n
for a line break.
* @property {number} textAlpha=1 - The text alpha value.
* @property {Color} backgroundColor=0,0,0 - The background color.
* @property {number} backgroundAlpha=0.7 - The background alpha value.
@@ -1876,7 +1876,7 @@ QVector Overlays::findOverlays(const glm::vec3& center, float radius) {
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* parentID
set, otherwise the same value as position
.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
- * parentID
set, otherwise the same value as rotation
. Synonym: localOrientation
.
+ * parentID
set, otherwise the same value as rotation
. Synonym: localOrientation
.
* @property {boolean} ignorePickIntersection=false - If true
, picks ignore the overlay. ignoreRayIntersection
is a synonym.
* @property {boolean} drawInFront=false - If true
, the overlay is rendered in front of objects in the world, but behind the HUD.
* @property {boolean} drawHUDLayer=false - If true
, the overlay is rendered in front of everything, including the HUD.
@@ -1916,7 +1916,7 @@ QVector Overlays::findOverlays(const glm::vec3& center, float radius) {
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* parentID
set, otherwise the same value as position
.
* @property {Quat} localRotation - The orientation of the overlay relative to its parent if the overlay has a
- * parentID
set, otherwise the same value as rotation
. Synonym: localOrientation
.
+ * parentID
set, otherwise the same value as rotation
. Synonym: localOrientation
.
* @property {boolean} isSolid=false - Synonyms: solid
, isFilled
, and filled
.
* Antonyms: isWire
and wire
.
* @property {boolean} ignorePickIntersection=false - If true
, picks ignore the overlay. ignoreRayIntersection
is a synonym.
@@ -1927,46 +1927,46 @@ QVector Overlays::findOverlays(const glm::vec3& center, float radius) {
* @property {number} parentJointIndex=65535 - Integer value specifying the skeleton joint that the overlay is attached to if
* parentID
is an avatar skeleton. A value of 65535
means "no joint".
*
- * @property {number} startAt = 0 - The counter - clockwise angle from the overlay's x-axis that drawing starts at, in degrees.
- * @property {number} endAt = 360 - The counter - clockwise angle from the overlay's x-axis that drawing ends at, in degrees.
- * @property {number} outerRadius = 1 - The outer radius of the overlay, in meters.Synonym: radius< / code>.
- * @property {number} innerRadius = 0 - The inner radius of the overlay, in meters.
- * @property {Color} color = 255, 255, 255 - The color of the overlay.Setting this value also sets the values of
- * innerStartColor< / code>, innerEndColor< / code>, outerStartColor< / code>, and outerEndColor< / code>.
- * @property {Color} startColor - Sets the values of innerStartColor< / code> and outerStartColor< / code>.
- * Write - only.< / em>
- * @property {Color} endColor - Sets the values of innerEndColor< / code> and outerEndColor< / code>.
- * Write - only.< / em>
- * @property {Color} innerColor - Sets the values of innerStartColor< / code> and innerEndColor< / code>.
- * Write - only.< / em>
- * @property {Color} outerColor - Sets the values of outerStartColor< / code> and outerEndColor< / code>.
- * Write - only.< / em>
+ * @property {number} startAt = 0 - The counter - clockwise angle from the overlay's x-axis that drawing starts at in degrees.
+ * @property {number} endAt = 360 - The counter - clockwise angle from the overlay's x-axis that drawing ends at in degrees.
+ * @property {number} outerRadius = 1 - The outer radius of the overlay in meters. Synonym: radius
.
+ * @property {number} innerRadius = 0 - The inner radius of the overlay in meters.
+ * @property {Color} color = 255, 255, 255 - The color of the overlay. Setting this value also sets the values of
+ * innerStartColor
, innerEndColor
, outerStartColor
, and outerEndColor
.
+ * @property {Color} startColor - Sets the values of innerStartColor
and outerStartColor
.
+ * Write - only.
+ * @property {Color} endColor - Sets the values of innerEndColor
and outerEndColor
.
+ * Write - only.
+ * @property {Color} innerColor - Sets the values of innerStartColor
and innerEndColor
.
+ * Write - only.
+ * @property {Color} outerColor - Sets the values of outerStartColor
and outerEndColor
.
+ * Write - only.
* @property {Color} innerStartcolor - The color at the inner start point of the overlay.
* @property {Color} innerEndColor - The color at the inner end point of the overlay.
* @property {Color} outerStartColor - The color at the outer start point of the overlay.
* @property {Color} outerEndColor - The color at the outer end point of the overlay.
- * @property {number} alpha = 0.5 - The opacity of the overlay, 0.0< / code> -1.0< / code>.Setting this value also sets
- * the values of innerStartAlpha< / code>, innerEndAlpha< / code>, outerStartAlpha< / code>, and
- * outerEndAlpha< / code>.Synonym: Alpha< / code>; write - only< / em>.
- * @property {number} startAlpha - Sets the values of innerStartAlpha< / code> and outerStartAlpha< / code>.
- * Write - only.< / em>
- * @property {number} endAlpha - Sets the values of innerEndAlpha< / code> and outerEndAlpha< / code>.
- * Write - only.< / em>
- * @property {number} innerAlpha - Sets the values of innerStartAlpha< / code> and innerEndAlpha< / code>.
- * Write - only.< / em>
- * @property {number} outerAlpha - Sets the values of outerStartAlpha< / code> and outerEndAlpha< / code>.
- * Write - only.< / em>
+ * @property {number} alpha = 0.5 - The opacity of the overlay, 0.0
-1.0
. Setting this value also sets
+ * the values of innerStartAlpha
, innerEndAlpha
, outerStartAlpha
, and
+ * outerEndAlpha
. Synonym: Alpha
; write - only.
+ * @property {number} startAlpha - Sets the values of innerStartAlpha
and outerStartAlpha
.
+ * Write - only.
+ * @property {number} endAlpha - Sets the values of innerEndAlpha
and outerEndAlpha
.
+ * Write - only.
+ * @property {number} innerAlpha - Sets the values of innerStartAlpha
and innerEndAlpha
.
+ * Write - only.
+ * @property {number} outerAlpha - Sets the values of outerStartAlpha
and outerEndAlpha
.
+ * Write - only.
* @property {number} innerStartAlpha = 0 - The alpha at the inner start point of the overlay.
* @property {number} innerEndAlpha = 0 - The alpha at the inner end point of the overlay.
* @property {number} outerStartAlpha = 0 - The alpha at the outer start point of the overlay.
* @property {number} outerEndAlpha = 0 - The alpha at the outer end point of the overlay.
*
- * @property {boolean} hasTickMarks = false - If true< / code>, tick marks are drawn.
+ * @property {boolean} hasTickMarks = false - If true
, tick marks are drawn.
* @property {number} majorTickMarksAngle = 0 - The angle between major tick marks, in degrees.
* @property {number} minorTickMarksAngle = 0 - The angle between minor tick marks, in degrees.
- * @property {number} majorTickMarksLength = 0 - The length of the major tick marks, in meters.A positive value draws tick marks
+ * @property {number} majorTickMarksLength = 0 - The length of the major tick marks, in meters. A positive value draws tick marks
* outwards from the inner radius; a negative value draws tick marks inwards from the outer radius.
- * @property {number} minorTickMarksLength = 0 - The length of the minor tick marks, in meters.A positive value draws tick marks
+ * @property {number} minorTickMarksLength = 0 - The length of the minor tick marks, in meters. A positive value draws tick marks
* outwards from the inner radius; a negative value draws tick marks inwards from the outer radius.
* @property {Color} majorTickMarksColor = 0, 0, 0 - The color of the major tick marks.
* @property {Color} minorTickMarksColor = 0, 0, 0 - The color of the minor tick marks.
diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h
index 0136b7d125..6d58ecedec 100644
--- a/libraries/animation/src/AnimInverseKinematics.h
+++ b/libraries/animation/src/AnimInverseKinematics.h
@@ -59,6 +59,46 @@ public:
float getMaxErrorOnLastSolve() { return _maxErrorOnLastSolve; }
+ /**jsdoc
+ * Specifies the initial conditions of the IK solver.
+ *
+ *
+ * Value Name Description
+ *
+ *
+ * 0
RelaxToUnderPoses This is a blend: it is 15/16 PreviousSolution
+ * and 1/16 UnderPoses
. This provides some of the benefits of using UnderPoses
so that the
+ * underlying animation is still visible, while at the same time converging faster then using the
+ * UnderPoses
as the only initial solution.
+ * 1
RelaxToLimitCenterPoses This is a blend: it is 15/16
+ * PreviousSolution
and 1/16 LimitCenterPoses
. This should converge quickly because it is
+ * close to the previous solution, but still provides the benefits of avoiding limb locking.
+ * 2
PreviousSolution The IK system will begin to solve from the same position and
+ * orientations for each joint that was the result from the previous frame.
+ * Pros: As the end effectors typically do not move much from frame to frame, this is likely to converge quickly
+ * to a valid solution.
+ * Cons: If the previous solution resulted in an awkward or uncomfortable posture, the next frame will also be
+ * awkward and uncomfortable. It can also result in locked elbows and knees.
+ * 3
UnderPoses The IK occurs at one of the top-most layers. It has access to the
+ * full posture that was computed via canned animations and blends. We call this animated set of poses the "under
+ * pose". The under poses are what would be visible if IK was completely disabled. Using the under poses as the
+ * initial conditions of the CCD solve will cause some of the animated motion to be blended into the result of the
+ * IK. This can result in very natural results, especially if there are only a few IK targets enabled. On the other
+ * hand, because the under poses might be quite far from the desired end effector, it can converge slowly in some
+ * cases, causing it to never reach the IK target in the allotted number of iterations. Also, in situations where all
+ * of the IK targets are being controlled by external sensors, sometimes starting from the under poses can cause
+ * awkward motions from the underlying animations to leak into the IK result.
+ * 4
LimitCenterPoses This pose is taken to be the center of all the joint
+ * constraints. This can prevent the IK solution from getting locked or stuck at a particular constraint. For
+ * example, if the arm is pointing straight outward from the body, as the end effector moves towards the body, at
+ * some point the elbow should bend to accommodate. However, because the CCD solver is stuck at a local maximum, it
+ * will not rotate the elbow, unless the initial conditions already have the elbow bent, which is the case for
+ * LimitCenterPoses
. When all the IK targets are enabled, this result will provide a consistent starting
+ * point for each IK solve, hopefully resulting in a consistent, natural result.
+ *
+ *
+ * @typedef {number} MyAvatar.AnimIKSolutionSource
+ */
enum class SolutionSource {
RelaxToUnderPoses = 0,
RelaxToLimitCenterPoses,
diff --git a/libraries/animation/src/AnimOverlay.h b/libraries/animation/src/AnimOverlay.h
index 70929bd4e4..1ad4e100db 100644
--- a/libraries/animation/src/AnimOverlay.h
+++ b/libraries/animation/src/AnimOverlay.h
@@ -24,6 +24,37 @@ class AnimOverlay : public AnimNode {
public:
friend class AnimTests;
+ /**jsdoc
+ * Specifies sets of joints.
+ *
+ *
+ * Value Name Description
+ *
+ *
+ * 0
FullBodyBoneSet All joints.
+ * 1
UpperBodyBoneSet Only the "Spine" joint and its children.
+ * 2
LowerBodyBoneSet Only the leg joints and their children.
+ * 3
LeftArmBoneSet Joints that are the children of the "LeftShoulder"
+ * joint.
+ * 4
RightArmBoneSet Joints that are the children of the "RightShoulder"
+ * joint.
+ * 5
AboveTheHeadBoneSet Joints that are the children of the "Head"
+ * joint.
+ * 6
BelowTheHeadBoneSet Joints that are NOT the children of the "head"
+ * joint.
+ * 7
HeadOnlyBoneSet The "Head" joint.
+ * 8
SpineOnlyBoneSet The "Spine" joint.
+ * 9
EmptyBoneSet No joints.
+ * 10
LeftHandBoneSet joints that are the children of the "LeftHand"
+ * joint.
+ * 11
RightHandBoneSet Joints that are the children of the "RightHand"
+ * joint.
+ * 12
HipsOnlyBoneSet The "Hips" joint.
+ * 13
BothFeetBoneSet The "LeftFoot" and "RightFoot" joints.
+ *
+ *
+ * @typedef {number} MyAvatar.AnimOverlayBoneSet
+ */
enum BoneSet {
FullBodyBoneSet = 0,
UpperBodyBoneSet,
diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp
index 5bc2021e5e..1f9e72bf28 100644
--- a/libraries/animation/src/Flow.cpp
+++ b/libraries/animation/src/Flow.cpp
@@ -67,17 +67,23 @@ void FlowCollisionSystem::addCollisionSphere(int jointIndex, const FlowCollision
auto collision = FlowCollisionSphere(jointIndex, settings, isTouch);
collision.setPosition(position);
if (isSelfCollision) {
- _selfCollisions.push_back(collision);
+ if (!isTouch) {
+ _selfCollisions.push_back(collision);
+ } else {
+ _selfTouchCollisions.push_back(collision);
+ }
} else {
_othersCollisions.push_back(collision);
}
-
};
+
void FlowCollisionSystem::resetCollisions() {
_allCollisions.clear();
_othersCollisions.clear();
+ _selfTouchCollisions.clear();
_selfCollisions.clear();
}
+
FlowCollisionResult FlowCollisionSystem::computeCollision(const std::vector collisions) {
FlowCollisionResult result;
if (collisions.size() > 1) {
@@ -106,6 +112,10 @@ void FlowCollisionSystem::setScale(float scale) {
_selfCollisions[j]._radius = _selfCollisions[j]._initialRadius * scale;
_selfCollisions[j]._offset = _selfCollisions[j]._initialOffset * scale;
}
+ for (size_t j = 0; j < _selfTouchCollisions.size(); j++) {
+ _selfTouchCollisions[j]._radius = _selfTouchCollisions[j]._initialRadius * scale;
+ _selfTouchCollisions[j]._offset = _selfTouchCollisions[j]._initialOffset * scale;
+ }
};
std::vector FlowCollisionSystem::checkFlowThreadCollisions(FlowThread* flowThread) {
@@ -178,9 +188,9 @@ void FlowCollisionSystem::setCollisionSettingsByJoint(int jointIndex, const Flow
}
void FlowCollisionSystem::prepareCollisions() {
_allCollisions.clear();
- _allCollisions.resize(_selfCollisions.size() + _othersCollisions.size());
- std::copy(_selfCollisions.begin(), _selfCollisions.begin() + _selfCollisions.size(), _allCollisions.begin());
- std::copy(_othersCollisions.begin(), _othersCollisions.begin() + _othersCollisions.size(), _allCollisions.begin() + _selfCollisions.size());
+ _allCollisions.insert(_allCollisions.end(), _selfCollisions.begin(), _selfCollisions.end());
+ _allCollisions.insert(_allCollisions.end(), _othersCollisions.begin(), _othersCollisions.end());
+ _allCollisions.insert(_allCollisions.end(), _selfTouchCollisions.begin(), _selfTouchCollisions.end());
_othersCollisions.clear();
}
@@ -273,18 +283,20 @@ void FlowJoint::setRecoveryPosition(const glm::vec3& recoveryPosition) {
}
void FlowJoint::update(float deltaTime) {
- glm::vec3 accelerationOffset = glm::vec3(0.0f);
- if (_settings._stiffness > 0.0f) {
- glm::vec3 recoveryVector = _recoveryPosition - _currentPosition;
- float recoveryFactor = powf(_settings._stiffness, 3.0f);
- accelerationOffset = recoveryVector * recoveryFactor;
- }
- FlowNode::update(deltaTime, accelerationOffset);
- if (_anchored) {
- if (!_isHelper) {
- _currentPosition = _updatedPosition;
- } else {
- _currentPosition = _parentPosition;
+ if (_settings._active) {
+ glm::vec3 accelerationOffset = glm::vec3(0.0f);
+ if (_settings._stiffness > 0.0f) {
+ glm::vec3 recoveryVector = _recoveryPosition - _currentPosition;
+ float recoveryFactor = powf(_settings._stiffness, 3.0f);
+ accelerationOffset = recoveryVector * recoveryFactor;
+ }
+ FlowNode::update(deltaTime, accelerationOffset);
+ if (_anchored) {
+ if (!_isHelper) {
+ _currentPosition = _updatedPosition;
+ } else {
+ _currentPosition = _parentPosition;
+ }
}
}
};
@@ -674,6 +686,14 @@ bool Flow::updateRootFramePositions(const AnimPoseVec& absolutePoses, size_t thr
return true;
}
+void Flow::updateCollisionJoint(FlowCollisionSphere& collision, AnimPoseVec& absolutePoses) {
+ glm::quat jointRotation;
+ getJointPositionInWorldFrame(absolutePoses, collision._jointIndex, collision._position, _entityPosition, _entityRotation);
+ getJointRotationInWorldFrame(absolutePoses, collision._jointIndex, jointRotation, _entityRotation);
+ glm::vec3 worldOffset = jointRotation * collision._offset;
+ collision._position = collision._position + worldOffset;
+}
+
void Flow::updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses) {
updateAbsolutePoses(relativePoses, absolutePoses);
for (auto &jointData : _flowJointData) {
@@ -695,11 +715,11 @@ void Flow::updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses)
}
auto &selfCollisions = _collisionSystem.getSelfCollisions();
for (auto &collision : selfCollisions) {
- glm::quat jointRotation;
- getJointPositionInWorldFrame(absolutePoses, collision._jointIndex, collision._position, _entityPosition, _entityRotation);
- getJointRotationInWorldFrame(absolutePoses, collision._jointIndex, jointRotation, _entityRotation);
- glm::vec3 worldOffset = jointRotation * collision._offset;
- collision._position = collision._position + worldOffset;
+ updateCollisionJoint(collision, absolutePoses);
+ }
+ auto &selfTouchCollisions = _collisionSystem.getSelfTouchCollisions();
+ for (auto &collision : selfTouchCollisions) {
+ updateCollisionJoint(collision, absolutePoses);
}
_collisionSystem.prepareCollisions();
}
@@ -710,7 +730,7 @@ void Flow::setJoints(AnimPoseVec& relativePoses, const std::vector& overri
for (int jointIndex : joints) {
auto &joint = _flowJointData[jointIndex];
if (jointIndex >= 0 && jointIndex < (int)relativePoses.size() && !overrideFlags[jointIndex]) {
- relativePoses[jointIndex].rot() = joint.getCurrentRotation();
+ relativePoses[jointIndex].rot() = joint.getSettings()._active ? joint.getCurrentRotation() : joint.getInitialRotation();
}
}
}
diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h
index ad81c2be77..5dc1a3ba3e 100644
--- a/libraries/animation/src/Flow.h
+++ b/libraries/animation/src/Flow.h
@@ -140,6 +140,7 @@ public:
std::vector checkFlowThreadCollisions(FlowThread* flowThread);
std::vector& getSelfCollisions() { return _selfCollisions; };
+ std::vector& getSelfTouchCollisions() { return _selfTouchCollisions; };
void setOthersCollisions(const std::vector& othersCollisions) { _othersCollisions = othersCollisions; }
void prepareCollisions();
void resetCollisions();
@@ -150,9 +151,11 @@ public:
void setActive(bool active) { _active = active; }
bool getActive() const { return _active; }
const std::vector& getCollisions() const { return _selfCollisions; }
+ void clearSelfCollisions() { _selfCollisions.clear(); }
protected:
std::vector _selfCollisions;
std::vector _othersCollisions;
+ std::vector _selfTouchCollisions;
std::vector _allCollisions;
float _scale { 1.0f };
bool _active { false };
@@ -210,7 +213,7 @@ public:
bool isHelper() const { return _isHelper; }
const FlowPhysicsSettings& getSettings() { return _settings; }
- void setSettings(const FlowPhysicsSettings& settings) { _settings = settings; }
+ void setSettings(const FlowPhysicsSettings& settings) { _settings = settings; _initialRadius = _settings._radius; }
const glm::vec3& getCurrentPosition() const { return _currentPosition; }
int getIndex() const { return _index; }
@@ -222,6 +225,7 @@ public:
const glm::quat& getCurrentRotation() const { return _currentRotation; }
const glm::vec3& getCurrentTranslation() const { return _initialTranslation; }
const glm::vec3& getInitialPosition() const { return _initialPosition; }
+ const glm::quat& getInitialRotation() const { return _initialRotation; }
bool isColliding() const { return _colliding; }
protected:
@@ -297,6 +301,7 @@ public:
void setPhysicsSettingsForGroup(const QString& group, const FlowPhysicsSettings& settings);
const std::map& getGroupSettings() const { return _groupSettings; }
void cleanUp();
+ void updateScale() { setScale(_scale); }
signals:
void onCleanup();
@@ -311,6 +316,7 @@ private:
void setJoints(AnimPoseVec& relativePoses, const std::vector& overrideFlags);
void updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses);
+ void updateCollisionJoint(FlowCollisionSphere& collision, AnimPoseVec& absolutePoses);
bool updateRootFramePositions(const AnimPoseVec& absolutePoses, size_t threadIndex);
void updateGroupSettings(const QString& group, const FlowPhysicsSettings& settings);
void setScale(float scale);
diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h
index 57eaff9c30..564dba7f05 100644
--- a/libraries/animation/src/IKTarget.h
+++ b/libraries/animation/src/IKTarget.h
@@ -16,6 +16,27 @@ const float HACK_HMD_TARGET_WEIGHT = 8.0f;
class IKTarget {
public:
+ /**jsdoc
+ * An IK target type.
+ *
+ *
+ * Value Name Description
+ *
+ *
+ * 0
RotationAndPosition Attempt to reach the rotation and position end
+ * effector.
+ * 1
RotationOnly Attempt to reach the end effector rotation only.
+ * 2
HmdHead Deprecated: A special mode of IK that would attempt
+ * to prevent unnecessary bending of the spine.
+ * 3
HipsRelativeRotationAndPosition Attempt to reach a rotation and position end
+ * effector that is not in absolute rig coordinates but is offset by the avatar hips translation.
+ * 4
Spline Use a cubic Hermite spline to model the human spine. This prevents
+ * kinks in the spine and allows for a small amount of stretch and squash.
+ * 5
Unknown IK is disabled.
+ *
+ *
+ * @typedef {number} MyAvatar.IKTargetType
+ */
enum class Type {
RotationAndPosition,
RotationOnly,
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 07bdfde189..43e94d23e8 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -88,6 +88,218 @@ static const QString MAIN_STATE_MACHINE_RIGHT_HAND_ROTATION("mainStateMachineRig
static const QString MAIN_STATE_MACHINE_RIGHT_HAND_POSITION("mainStateMachineRightHandPosition");
+/**jsdoc
+ * An AnimStateDictionary
object may have the following properties. It may also have other properties, set by
+ * scripts.
+ * Warning: These properties are subject to change.
+ *
+ *
+ * Name Type Description
+ *
+ *
+ * userAnimNone
boolean true
when no user overrideAnimation is
+ * playing.
+ * userAnimA
boolean true
when a user overrideAnimation is
+ * playing.
+ * userAnimB
boolean true
when a user overrideAnimation is
+ * playing.
+ *
+ * sine
number Oscillating sine wave.
+ * moveForwardSpeed
number Controls the blend between the various forward walking
+ * & running animations.
+ * moveBackwardSpeed
number Controls the blend between the various backward walking
+ * & running animations.
+ * moveLateralSpeed
number Controls the blend between the various sidestep walking
+ * & running animations.
+ *
+ * isMovingForward
boolean true
if the avatar is moving
+ * forward.
+ * isMovingBackward
boolean true
if the avatar is moving
+ * backward.
+ * isMovingRight
boolean true
if the avatar is moving to the
+ * right.
+ * isMovingLeft
boolean true
if the avatar is moving to the
+ * left.
+ * isMovingRightHmd
boolean true
if the avatar is moving to the right
+ * while the user is in HMD mode.
+ * isMovingLeftHmd
boolean true
if the avatar is moving to the left while
+ * the user is in HMD mode.
+ * isNotMoving
boolean true
if the avatar is stationary.
+ *
+ * isTurningRight
boolean true
if the avatar is turning
+ * clockwise.
+ * isTurningLeft
boolean true
if the avatar is turning
+ * counter-clockwise.
+ * isNotTurning
boolean true
if the avatar is not turning.
+ * isFlying
boolean true
if the avatar is flying.
+ * isNotFlying
boolean true
if the avatar is not flying.
+ * isTakeoffStand
boolean true
if the avatar is about to execute a
+ * standing jump.
+ * isTakeoffRun
boolean true
if the avatar is about to execute a running
+ * jump.
+ * isNotTakeoff
boolean true
if the avatar is not jumping.
+ * isInAirStand
boolean true
if the avatar is in the air after a standing
+ * jump.
+ * isInAirRun
boolean true
if the avatar is in the air after a running
+ * jump.
+ * isNotInAir
boolean true
if the avatar on the ground.
+ *
+ * inAirAlpha
number Used to interpolate between the up, apex, and down in-air
+ * animations.
+ * ikOverlayAlpha
number The blend between upper body and spline IK versus the
+ * underlying animation
+ *
+ * headPosition
{@link Vec3} The desired position of the Head
joint in
+ * rig coordinates.
+ * headRotation
{@link Quat} The desired orientation of the Head
joint in
+ * rig coordinates.
+ * headType
{@link MyAvatar.IKTargetType|IKTargetType} The type of IK used for the
+ * head.
+ * headWeight
number How strongly the head chain blends with the other IK
+ * chains.
+ *
+ * leftHandPosition
{@link Vec3} The desired position of the LeftHand
+ * joint in rig coordinates.
+ * leftHandRotation
{@link Quat} The desired orientation of the LeftHand
+ * joint in rig coordinates.
+ * leftHandType
{@link MyAvatar.IKTargetType|IKTargetType} The type of IK used for the
+ * left arm.
+ * leftHandPoleVectorEnabled
boolean When true
, the elbow angle is
+ * controlled by the rightHandPoleVector
property value. Otherwise the elbow direction comes from the
+ * underlying animation.
+ * leftHandPoleReferenceVector
{@link Vec3} The direction of the elbow in the local
+ * coordinate system of the elbow.
+ * leftHandPoleVector
{@link Vec3} The direction the elbow should point in rig
+ * coordinates.
+ *
+ * rightHandPosition
{@link Vec3} The desired position of the RightHand
+ * joint in rig coordinates.
+ * rightHandRotation
{@link Quat} The desired orientation of the
+ * RightHand
joint in rig coordinates.
+ * rightHandType
{@link MyAvatar.IKTargetType|IKTargetType} The type of IK used for
+ * the right arm.
+ * rightHandPoleVectorEnabled
boolean When true
, the elbow angle is
+ * controlled by the rightHandPoleVector
property value. Otherwise the elbow direction comes from the
+ * underlying animation.
+ * rightHandPoleReferenceVector
{@link Vec3} The direction of the elbow in the local
+ * coordinate system of the elbow.
+ * rightHandPoleVector
{@link Vec3} The direction the elbow should point in rig
+ * coordinates.
+ *
+ * leftFootIKEnabled
boolean true
if IK is enabled for the left
+ * foot.
+ * rightFootIKEnabled
boolean true
if IK is enabled for the right
+ * foot.
+ *
+ * leftFootIKPositionVar
string The name of the source for the desired position
+ * of the LeftFoot
joint. If not set, the foot rotation of the underlying animation will be used.
+ * leftFootIKRotationVar
string The name of the source for the desired rotation
+ * of the LeftFoot
joint. If not set, the foot rotation of the underlying animation will be used.
+ * leftFootPoleVectorEnabled
boolean When true
, the knee angle is
+ * controlled by the leftFootPoleVector
property value. Otherwise the knee direction comes from the
+ * underlying animation.
+ * leftFootPoleVector
{@link Vec3} The direction the knee should face in rig
+ * coordinates.
+ * rightFootIKPositionVar
string The name of the source for the desired position
+ * of the RightFoot
joint. If not set, the foot rotation of the underlying animation will be used.
+ * rightFootIKRotationVar
string The name of the source for the desired rotation
+ * of the RightFoot
joint. If not set, the foot rotation of the underlying animation will be used.
+ * rightFootPoleVectorEnabled
boolean When true
, the knee angle is
+ * controlled by the rightFootPoleVector
property value. Otherwise the knee direction comes from the
+ * underlying animation.
+ * rightFootPoleVector
{@link Vec3} The direction the knee should face in rig
+ * coordinates.
+ *
+ * isTalking
boolean true
if the avatar is talking.
+ * notIsTalking
boolean true
if the avatar is not talking.
+ *
+ * solutionSource
{@link MyAvatar.AnimIKSolutionSource|AnimIKSolutionSource}
+ * Determines the initial conditions of the IK solver.
+ * defaultPoseOverlayAlpha
number Controls the blend between the main animation state
+ * machine and the default pose. Mostly used during full body tracking so that walking & jumping animations do not
+ * affect the IK of the figure.
+ * defaultPoseOverlayBoneSet
{@link MyAvatar.AnimOverlayBoneSet|AnimOverlayBoneSet}
+ * Specifies which bones will be replace by the source overlay.
+ * hipsType
{@link MyAvatar.IKTargetType|IKTargetType} The type of IK used for the
+ * hips.
+ * hipsPosition
{@link Vec3} The desired position of Hips
joint in rig
+ * coordinates.
+ * hipsRotation
{@link Quat} the desired orientation of the Hips
joint in
+ * rig coordinates.
+ * spine2Type
{@link MyAvatar.IKTargetType|IKTargetType} The type of IK used for the
+ * Spine2
joint.
+ * spine2Position
{@link Vec3} The desired position of the Spine2
joint
+ * in rig coordinates.
+ * spine2Rotation
{@link Quat} The desired orientation of the Spine2
+ * joint in rig coordinates.
+ *
+ * leftFootIKAlpha
number Blends between full IK for the leg and the underlying
+ * animation.
+ * rightFootIKAlpha
number Blends between full IK for the leg and the underlying
+ * animation.
+ * hipsWeight
number How strongly the hips target blends with the IK solution for
+ * other IK chains.
+ * leftHandWeight
number How strongly the left hand blends with IK solution of other
+ * IK chains.
+ * rightHandWeight
number How strongly the right hand blends with IK solution of other
+ * IK chains.
+ * spine2Weight
number How strongly the spine2 chain blends with the rest of the IK
+ * solution.
+ *
+ * leftHandOverlayAlpha
number Used to blend in the animated hand gesture poses, such
+ * as point and thumbs up.
+ * leftHandGraspAlpha
number Used to blend between an open hand and a closed hand.
+ * Usually changed as you squeeze the trigger of the hand controller.
+ * rightHandOverlayAlpha
number Used to blend in the animated hand gesture poses,
+ * such as point and thumbs up.
+ * rightHandGraspAlpha
number Used to blend between an open hand and a closed hand.
+ * Usually changed as you squeeze the trigger of the hand controller.
+ * isLeftIndexPoint
boolean true
if the left hand should be
+ * pointing.
+ * isLeftThumbRaise
boolean true
if the left hand should be
+ * thumbs-up.
+ * isLeftIndexPointAndThumbRaise
boolean true
if the left hand should be
+ * pointing and thumbs-up.
+ * isLeftHandGrasp
boolean true
if the left hand should be at rest,
+ * grasping the controller.
+ * isRightIndexPoint
boolean true
if the right hand should be
+ * pointing.
+ * isRightThumbRaise
boolean true
if the right hand should be
+ * thumbs-up.
+ * isRightIndexPointAndThumbRaise
boolean true
if the right hand should
+ * be pointing and thumbs-up.
+ * isRightHandGrasp
boolean true
if the right hand should be at rest,
+ * grasping the controller.
+ *
+ *
+ *
+ * Note: Rig coordinates are +z
forward and +y
up.
+ * @typedef {object} MyAvatar.AnimStateDictionary
+ */
+// Note: The following animVars are intentionally not documented:
+// - leftFootPosition
+// - leftFootRotation
+// - rightFooKPosition
+// - rightFooKRotation
+// Note: The following items aren't set in the code below but are still intentionally documented:
+// - leftFootIKAlpha
+// - rightFootIKAlpha
+// - hipsWeight
+// - leftHandWeight
+// - rightHandWeight
+// - spine2Weight
+// - rightHandOverlayAlpha
+// - rightHandGraspAlpha
+// - leftHandOverlayAlpha
+// - leftHandGraspAlpha
+// - isRightIndexPoint
+// - isRightThumbRaise
+// - isRightIndexPointAndThumbRaise
+// - isRightHandGrasp
+// - isLeftIndexPoint
+// - isLeftThumbRaise
+// - isLeftIndexPointAndThumbRaise
+// - isLeftHandGrasp
Rig::Rig() {
// Ensure thread-safe access to the rigRegistry.
std::lock_guard guard(rigRegistryMutex);
@@ -1210,7 +1422,8 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons
_networkAnimState.blendTime += deltaTime;
alpha = _computeNetworkAnimation ? (_networkAnimState.blendTime / TOTAL_BLEND_TIME) : (1.0f - (_networkAnimState.blendTime / TOTAL_BLEND_TIME));
alpha = glm::clamp(alpha, 0.0f, 1.0f);
- for (size_t i = 0; i < _networkPoseSet._relativePoses.size(); i++) {
+ size_t numJoints = std::min(_networkPoseSet._relativePoses.size(), _internalPoseSet._relativePoses.size());
+ for (size_t i = 0; i < numJoints; i++) {
_networkPoseSet._relativePoses[i].blend(_internalPoseSet._relativePoses[i], alpha);
}
}
diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 9d645a1dbf..c537fea646 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -1052,7 +1052,7 @@ void AudioClient::setReverbOptions(const AudioEffectOptions* options) {
void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
// If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here.
bool hasReverb = _reverb || _receivedAudioStream.hasReverb();
- if (_muted || !_audioOutput || (!_shouldEchoLocally && !hasReverb)) {
+ if ((_muted && !_shouldEchoLocally) || !_audioOutput || (!_shouldEchoLocally && !hasReverb)) {
return;
}
@@ -1368,7 +1368,9 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) {
memset(_localScratchBuffer, 0, bytesToRead);
if (0 < injectorBuffer->readData((char*)_localScratchBuffer, bytesToRead)) {
- float gain = options.volume;
+ bool isSystemSound = !options.positionSet && !options.ambisonic;
+
+ float gain = options.volume * (isSystemSound ? _systemInjectorGain : _localInjectorGain);
if (options.ambisonic) {
diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h
index a153f22bf3..7608bf5cdb 100644
--- a/libraries/audio-client/src/AudioClient.h
+++ b/libraries/audio-client/src/AudioClient.h
@@ -241,6 +241,8 @@ public slots:
void setInputVolume(float volume, bool emitSignal = true);
void setReverb(bool reverb);
void setReverbOptions(const AudioEffectOptions* options);
+ void setLocalInjectorGain(float gain) { _localInjectorGain = gain; };
+ void setSystemInjectorGain(float gain) { _systemInjectorGain = gain; };
void outputNotify();
@@ -395,6 +397,8 @@ private:
int16_t* _outputScratchBuffer { NULL };
// for local audio (used by audio injectors thread)
+ std::atomic _localInjectorGain { 1.0f };
+ std::atomic _systemInjectorGain { 1.0f };
float _localMixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
int16_t _localScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC];
float* _localOutputMixBuffer { NULL };
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
index 6026367440..b4683d6032 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h
@@ -127,7 +127,12 @@ private:
class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaModelPayload {
Q_OBJECT
- // This property has JSDoc in MyAvatar.h.
+ /*jsdoc
+ * @comment IMPORTANT: The JSDoc for the following properties should be copied to MyAvatar.h.
+ *
+ * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the
+ * registration point of the 3D model.
+ */
Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset)
public:
@@ -196,36 +201,52 @@ public:
virtual QStringList getJointNames() const override;
/**jsdoc
+ * Gets the default rotation of a joint (in the current avatar) relative to its parent.
+ * For information on the joint hierarchy used, see
+ * Avatar Standards.
* @function MyAvatar.getDefaultJointRotation
- * @param {number} index
- * @returns {Quat}
+ * @param {number} index - The joint index.
+ * @returns {Quat} The default rotation of the joint if the joint index is valid, otherwise {@link Quat(0)|Quat.IDENTITY}.
*/
Q_INVOKABLE virtual glm::quat getDefaultJointRotation(int index) const;
/**jsdoc
+ * Gets the default translation of a joint (in the current avatar) relative to its parent, in model coordinates.
+ * Warning: These coordinates are not necessarily in meters.
+ * For information on the joint hierarchy used, see
+ * Avatar Standards.
* @function MyAvatar.getDefaultJointTranslation
- * @param {number} index
- * @returns {Vec3}
+ * @param {number} index - The joint index.
+ * @returns {Vec3} The default translation of the joint (in model coordinates) if the joint index is valid, otherwise
+ * {@link Vec3(0)|Vec3.ZERO}.
*/
Q_INVOKABLE virtual glm::vec3 getDefaultJointTranslation(int index) const;
/**jsdoc
- * Provides read only access to the default joint rotations in avatar coordinates.
+ * Gets the default joint rotations in avatar coordinates.
* The default pose of the avatar is defined by the position and orientation of all bones
* in the avatar's model file. Typically this is a T-pose.
* @function MyAvatar.getAbsoluteDefaultJointRotationInObjectFrame
- * @param index {number} index number
- * @returns {Quat} The rotation of this joint in avatar coordinates.
+ * @param index {number} - The joint index.
+ * @returns {Quat} The default rotation of the joint in avatar coordinates.
+ * @example Report the default rotation of your avatar's head joint relative to your avatar.
+ * var headIndex = MyAvatar.getJointIndex("Head");
+ * var defaultHeadRotation = MyAvatar.getAbsoluteDefaultJointRotationInObjectFrame(headIndex);
+ * print("Default head rotation: " + JSON.stringify(Quat.safeEulerAngles(defaultHeadRotation))); // Degrees
*/
Q_INVOKABLE virtual glm::quat getAbsoluteDefaultJointRotationInObjectFrame(int index) const;
/**jsdoc
- * Provides read only access to the default joint translations in avatar coordinates.
+ * Gets the default joint translations in avatar coordinates.
* The default pose of the avatar is defined by the position and orientation of all bones
* in the avatar's model file. Typically this is a T-pose.
* @function MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame
- * @param index {number} index number
- * @returns {Vec3} The position of this joint in avatar coordinates.
+ * @param index {number} - The joint index.
+ * @returns {Vec3} The default position of the joint in avatar coordinates.
+ * @example Report the default translation of your avatar's head joint relative to your avatar.
+ * var headIndex = MyAvatar.getJointIndex("Head");
+ * var defaultHeadTranslation = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(headIndex);
+ * print("Default head translation: " + JSON.stringify(defaultHeadTranslation));
*/
Q_INVOKABLE virtual glm::vec3 getAbsoluteDefaultJointTranslationInObjectFrame(int index) const;
@@ -233,59 +254,88 @@ public:
virtual glm::vec3 getAbsoluteJointScaleInObjectFrame(int index) const override;
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
+
+ /**jsdoc
+ * Sets the rotation of a joint relative to the avatar.
+ * Warning: Not able to be used in the MyAvatar
API.
+ * @function MyAvatar.setAbsoluteJointRotationInObjectFrame
+ * @param {number} index - The index of the joint. Not used.
+ * @param {Quat} rotation - The rotation of the joint relative to the avatar. Not used.
+ * @returns {boolean} false
.
+ */
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
+
+ /**jsdoc
+ * Sets the translation of a joint relative to the avatar.
+ * Warning: Not able to be used in the MyAvatar
API.
+ * @function MyAvatar.setAbsoluteJointTranslationInObjectFrame
+ * @param {number} index - The index of the joint. Not used.
+ * @param {Vec3} translation - The translation of the joint relative to the avatar. Not used.
+ * @returns {boolean} false
.
+ */
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
virtual glm::vec3 getSpine2SplineOffset() const { return _spine2SplineOffset; }
virtual float getSpine2SplineRatio() const { return _spine2SplineRatio; }
// world-space to avatar-space rigconversion functions
/**jsdoc
- * @function MyAvatar.worldToJointPoint
- * @param {Vec3} position
- * @param {number} [jointIndex=-1]
- * @returns {Vec3}
- */
+ * Transforms a position in world coordinates to a position in a joint's coordinates, or avatar coordinates if no joint is
+ * specified.
+ * @function MyAvatar.worldToJointPoint
+ * @param {Vec3} position - The position in world coordinates.
+ * @param {number} [jointIndex=-1] - The index of the joint.
+ * @returns {Vec3} The position in the joint's coordinate system, or avatar coordinate system if no joint is specified.
+ */
Q_INVOKABLE glm::vec3 worldToJointPoint(const glm::vec3& position, const int jointIndex = -1) const;
/**jsdoc
- * @function MyAvatar.worldToJointDirection
- * @param {Vec3} direction
- * @param {number} [jointIndex=-1]
- * @returns {Vec3}
- */
+ * Transforms a direction in world coordinates to a direction in a joint's coordinates, or avatar coordinates if no joint
+ * is specified.
+ * @function MyAvatar.worldToJointDirection
+ * @param {Vec3} direction - The direction in world coordinates.
+ * @param {number} [jointIndex=-1] - The index of the joint.
+ * @returns {Vec3} The direction in the joint's coordinate system, or avatar coordinate system if no joint is specified.
+ */
Q_INVOKABLE glm::vec3 worldToJointDirection(const glm::vec3& direction, const int jointIndex = -1) const;
/**jsdoc
- * @function MyAvatar.worldToJointRotation
- * @param {Quat} rotation
- * @param {number} [jointIndex=-1]
- * @returns {Quat}
+ * Transforms a rotation in world coordinates to a rotation in a joint's coordinates, or avatar coordinates if no joint is
+ * specified.
+ * @function MyAvatar.worldToJointRotation
+ * @param {Quat} rotation - The rotation in world coordinates.
+ * @param {number} [jointIndex=-1] - The index of the joint.
+ * @returns {Quat} The rotation in the joint's coordinate system, or avatar coordinate system if no joint is specified.
*/
Q_INVOKABLE glm::quat worldToJointRotation(const glm::quat& rotation, const int jointIndex = -1) const;
-
/**jsdoc
- * @function MyAvatar.jointToWorldPoint
- * @param {vec3} position
- * @param {number} [jointIndex=-1]
- * @returns {Vec3}
- */
+ * Transforms a position in a joint's coordinates, or avatar coordinates if no joint is specified, to a position in world
+ * coordinates.
+ * @function MyAvatar.jointToWorldPoint
+ * @param {Vec3} position - The position in joint coordinates, or avatar coordinates if no joint is specified.
+ * @param {number} [jointIndex=-1] - The index of the joint.
+ * @returns {Vec3} The position in world coordinates.
+ */
Q_INVOKABLE glm::vec3 jointToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const;
/**jsdoc
- * @function MyAvatar.jointToWorldDirection
- * @param {Vec3} direction
- * @param {number} [jointIndex=-1]
- * @returns {Vec3}
- */
+ * Transforms a direction in a joint's coordinates, or avatar coordinates if no joint is specified, to a direction in world
+ * coordinates.
+ * @function MyAvatar.jointToWorldDirection
+ * @param {Vec3} direction - The direction in joint coordinates, or avatar coordinates if no joint is specified.
+ * @param {number} [jointIndex=-1] - The index of the joint.
+ * @returns {Vec3} The direction in world coordinates.
+ */
Q_INVOKABLE glm::vec3 jointToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const;
/**jsdoc
- * @function MyAvatar.jointToWorldRotation
- * @param {Quat} rotation
- * @param {number} [jointIndex=-1]
- * @returns {Quat}
- */
+ * Transforms a rotation in a joint's coordinates, or avatar coordinates if no joint is specified, to a rotation in world
+ * coordinates.
+ * @function MyAvatar.jointToWorldRotation
+ * @param {Quat} rotation - The rotation in joint coordinates, or avatar coordinates if no joint is specified.
+ * @param {number} [jointIndex=-1] - The index of the joint.
+ * @returns {Quat} The rotation in world coordinates.
+ */
Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const;
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
@@ -297,7 +347,7 @@ public:
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
/**jsdoc
- * Set the offset applied to the current avatar. The offset adjusts the position that the avatar is rendered. For example,
+ * Sets the offset applied to the current avatar. The offset adjusts the position that the avatar is rendered. For example,
* with an offset of { x: 0, y: 0.1, z: 0 }
, your avatar will appear to be raised off the ground slightly.
* @function MyAvatar.setSkeletonOffset
* @param {Vec3} offset - The skeleton offset to set.
@@ -313,7 +363,7 @@ public:
Q_INVOKABLE void setSkeletonOffset(const glm::vec3& offset);
/**jsdoc
- * Get the offset applied to the current avatar. The offset adjusts the position that the avatar is rendered. For example,
+ * Gets the offset applied to the current avatar. The offset adjusts the position that the avatar is rendered. For example,
* with an offset of { x: 0, y: 0.1, z: 0 }
, your avatar will appear to be raised off the ground slightly.
* @function MyAvatar.getSkeletonOffset
* @returns {Vec3} The current skeleton offset.
@@ -325,7 +375,7 @@ public:
virtual glm::vec3 getSkeletonPosition() const;
/**jsdoc
- * Get the position of a joint in the current avatar.
+ * Gets the position of a joint in the current avatar.
* @function MyAvatar.getJointPosition
* @param {number} index - The index of the joint.
* @returns {Vec3} The position of the joint in world coordinates.
@@ -333,7 +383,7 @@ public:
Q_INVOKABLE glm::vec3 getJointPosition(int index) const;
/**jsdoc
- * Get the position of a joint in the current avatar.
+ * Gets the position of a joint in the current avatar.
* @function MyAvatar.getJointPosition
* @param {string} name - The name of the joint.
* @returns {Vec3} The position of the joint in world coordinates.
@@ -343,7 +393,7 @@ public:
Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const;
/**jsdoc
- * Get the position of the current avatar's neck in world coordinates.
+ * Gets the position of the current avatar's neck in world coordinates.
* @function MyAvatar.getNeckPosition
* @returns {Vec3} The position of the neck in world coordinates.
* @example Report the position of your avatar's neck.
@@ -352,8 +402,9 @@ public:
Q_INVOKABLE glm::vec3 getNeckPosition() const;
/**jsdoc
+ * Gets the current acceleration of the avatar.
* @function MyAvatar.getAcceleration
- * @returns {Vec3}
+ * @returns {Vec3} The current acceleration of the avatar.
*/
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
@@ -377,47 +428,55 @@ public:
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
float computeMass();
/**jsdoc
- * Get the position of the current avatar's feet (or rather, bottom of its collision capsule) in world coordinates.
+ * Gets the position of the current avatar's feet (or rather, bottom of its collision capsule) in world coordinates.
* @function MyAvatar.getWorldFeetPosition
* @returns {Vec3} The position of the avatar's feet in world coordinates.
- */
+ */
Q_INVOKABLE glm::vec3 getWorldFeetPosition();
void setPositionViaScript(const glm::vec3& position) override;
void setOrientationViaScript(const glm::quat& orientation) override;
/**jsdoc
+ * Gets the ID of the entity of avatar that the avatar is parented to.
* @function MyAvatar.getParentID
- * @returns {Uuid}
+ * @returns {Uuid} The ID of the entity or avatar that the avatar is parented to. {@link Uuid|Uuid.NULL} if not parented.
*/
// This calls through to the SpatiallyNestable versions, but is here to expose these to JavaScript.
Q_INVOKABLE virtual const QUuid getParentID() const override { return SpatiallyNestable::getParentID(); }
/**jsdoc
+ * Sets the ID of the entity of avatar that the avatar is parented to.
* @function MyAvatar.setParentID
- * @param {Uuid} parentID
+ * @param {Uuid} parentID - The ID of the entity or avatar that the avatar should be parented to. Set to
+ * {@link Uuid|Uuid.NULL} to unparent.
*/
// This calls through to the SpatiallyNestable versions, but is here to expose these to JavaScript.
Q_INVOKABLE virtual void setParentID(const QUuid& parentID) override;
/**jsdoc
+ * Gets the joint of the entity or avatar that the avatar is parented to.
* @function MyAvatar.getParentJointIndex
- * @returns {number}
+ * @returns {number} The joint of the entity or avatar that the avatar is parented to. 65535
or
+ * -1
if parented to the entity or avatar's position and orientation rather than a joint.
*/
// This calls through to the SpatiallyNestable versions, but is here to expose these to JavaScript.
Q_INVOKABLE virtual quint16 getParentJointIndex() const override { return SpatiallyNestable::getParentJointIndex(); }
/**jsdoc
+ * Sets the joint of the entity or avatar that the avatar is parented to.
* @function MyAvatar.setParentJointIndex
- * @param {number} parentJointIndex
+ * @param {number} parentJointIndex - he joint of the entity or avatar that the avatar should be parented to. Use
+ * 65535
or -1
to parent to the entity or avatar's position and orientation rather than a
+ * joint.
*/
// This calls through to the SpatiallyNestable versions, but is here to expose these to JavaScript.
Q_INVOKABLE virtual void setParentJointIndex(quint16 parentJointIndex) override;
/**jsdoc
- * Returns an array of joints, where each joint is an object containing name, index, and parentIndex fields.
+ * Gets information on all the joints in the avatar's skeleton.
* @function MyAvatar.getSkeleton
- * @returns {MyAvatar.SkeletonJoint[]} A list of information about each joint in this avatar's skeleton.
+ * @returns {MyAvatar.SkeletonJoint[]} Information about each joint in the avatar's skeleton.
*/
/**jsdoc
* Information about a single joint in an Avatar's skeleton hierarchy.
@@ -443,8 +502,9 @@ public:
/**jsdoc
* @function MyAvatar.getSimulationRate
- * @param {string} [rateName=""]
- * @returns {number}
+ * @param {string} [rateName=""] - Rate name.
+ * @returns {number} Simulation rate.
+ * @deprecated This function is deprecated and will be removed.
*/
Q_INVOKABLE float getSimulationRate(const QString& rateName = QString("")) const;
@@ -500,6 +560,13 @@ public:
uint32_t appendSubMetaItems(render::ItemIDs& subItems);
signals:
+ /**jsdoc
+ * Triggered when the avatar's target scale is changed. The target scale is the desired scale of the avatar without any
+ * restrictions on permissible scale values imposed by the domain.
+ * @function MyAvatar.targetScaleChanged
+ * @param {number} targetScale - The avatar's target scale.
+ * @returns Signal
+ */
void targetScaleChanged(float targetScale);
public slots:
@@ -508,7 +575,7 @@ public slots:
// thread safe, will return last valid palm from cache
/**jsdoc
- * Get the position of the left palm in world coordinates.
+ * Gets the position of the left palm in world coordinates.
* @function MyAvatar.getLeftPalmPosition
* @returns {Vec3} The position of the left palm in world coordinates.
* @example Report the position of your avatar's left palm.
@@ -517,15 +584,16 @@ public slots:
glm::vec3 getLeftPalmPosition() const;
/**jsdoc
- * Get the rotation of the left palm in world coordinates.
+ * Gets the rotation of the left palm in world coordinates.
* @function MyAvatar.getLeftPalmRotation
* @returns {Quat} The rotation of the left palm in world coordinates.
* @example Report the rotation of your avatar's left palm.
* print(JSON.stringify(MyAvatar.getLeftPalmRotation()));
*/
glm::quat getLeftPalmRotation() const;
+
/**jsdoc
- * Get the position of the right palm in world coordinates.
+ * Gets the position of the right palm in world coordinates.
* @function MyAvatar.getRightPalmPosition
* @returns {Vec3} The position of the right palm in world coordinates.
* @example Report the position of your avatar's right palm.
@@ -542,21 +610,26 @@ public slots:
*/
glm::quat getRightPalmRotation() const;
+ /**jsdoc
+ * @function MyAvatar.setModelURLFinished
+ * @param {boolean} success
+ * @deprecated This function is deprecated and will be removed.
+ */
// hooked up to Model::setURLFinished signal
void setModelURLFinished(bool success);
/**jsdoc
* @function MyAvatar.rigReady
- * @returns {Signal}
+ * @deprecated This function is deprecated and will be removed.
*/
// Hooked up to Model::rigReady signal
void rigReady();
/**jsdoc
* @function MyAvatar.rigReset
- * @returns {Signal}
+ * @deprecated This function is deprecated and will be removed.
*/
- // Jooked up to Model::rigReset signal
+ // Hooked up to Model::rigReset signal
void rigReset();
protected:
diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp
index 26407c3564..39dfaa8a1a 100755
--- a/libraries/avatars/src/AvatarData.cpp
+++ b/libraries/avatars/src/AvatarData.cpp
@@ -1434,6 +1434,47 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
return numBytesRead;
}
+/**jsdoc
+ * The avatar mixer data comprises different types of data, with the data rates of each being tracked in kbps.
+ *
+ *
+ *
+ * Rate Name Description
+ *
+ *
+ * "globalPosition"
Incoming global position.
+ * "localPosition"
Incoming local position.
+ * "avatarBoundingBox"
Incoming avatar bounding box.
+ * "avatarOrientation"
Incoming avatar orientation.
+ * "avatarScale"
Incoming avatar scale.
+ * "lookAtPosition"
Incoming look-at position.
+ * "audioLoudness"
Incoming audio loudness.
+ * "sensorToWorkMatrix"
Incoming sensor-to-world matrix.
+ * "additionalFlags"
Incoming additional avatar flags.
+ * "parentInfo"
Incoming parent information.
+ * "faceTracker"
Incoming face tracker data.
+ * "jointData"
Incoming joint data.
+ * "jointDefaultPoseFlagsRate"
Incoming joint default pose flags.
+ * "farGrabJointRate"
Incoming far grab joint.
+ * "globalPositionOutbound"
Outgoing global position.
+ * "localPositionOutbound"
Outgoing local position.
+ * "avatarBoundingBoxOutbound"
Outgoing avatar bounding box.
+ * "avatarOrientationOutbound"
Outgoing avatar orientation.
+ * "avatarScaleOutbound"
Outgoing avatar scale.
+ * "lookAtPositionOutbound"
Outgoing look-at position.
+ * "audioLoudnessOutbound"
Outgoing audio loudness.
+ * "sensorToWorkMatrixOutbound"
Outgoing sensor-to-world matrix.
+ * "additionalFlagsOutbound"
Outgoing additional avatar flags.
+ * "parentInfoOutbound"
Outgoing parent information.
+ * "faceTrackerOutbound"
Outgoing face tracker data.
+ * "jointDataOutbound"
Outgoing joint data.
+ * "jointDefaultPoseFlagsOutbound"
Outgoing joint default pose flags.
+ * ""
When no rate name is specified, the total incoming data rate is provided.
+ *
+ *
+ *
+ * @typedef {string} AvatarDataRate
+ */
float AvatarData::getDataRate(const QString& rateName) const {
if (rateName == "") {
return _parseBufferRate.rate() / BYTES_PER_KILOBIT;
@@ -1495,6 +1536,35 @@ float AvatarData::getDataRate(const QString& rateName) const {
return 0.0f;
}
+/**jsdoc
+ * The avatar mixer data comprises different types of data updated at different rates, in Hz.
+ *
+ *
+ *
+ * Rate Name Description
+ *
+ *
+
+ * "globalPosition"
Global position.
+ * "localPosition"
Local position.
+ * "avatarBoundingBox"
Avatar bounding box.
+ * "avatarOrientation"
Avatar orientation.
+ * "avatarScale"
Avatar scale.
+ * "lookAtPosition"
Look-at position.
+ * "audioLoudness"
Audio loudness.
+ * "sensorToWorkMatrix"
Sensor-to-world matrix.
+ * "additionalFlags"
Additional avatar flags.
+ * "parentInfo"
Parent information.
+ * "faceTracker"
Face tracker data.
+ * "jointData"
Joint data.
+ * "farGrabJointData"
Far grab joint data.
+
+ * ""
When no rate name is specified, the overall update rate is provided.
+ *
+ *
+ *
+ * @typedef {string} AvatarUpdateRate
+ */
float AvatarData::getUpdateRate(const QString& rateName) const {
if (rateName == "") {
return _parseBufferUpdateRate.rate();
@@ -2730,13 +2800,16 @@ glm::vec3 AvatarData::getAbsoluteJointTranslationInObjectFrame(int index) const
}
/**jsdoc
+ * Information on an attachment worn by the avatar.
* @typedef {object} AttachmentData
- * @property {string} modelUrl
- * @property {string} jointName
- * @property {Vec3} translation
- * @property {Vec3} rotation
- * @property {number} scale
- * @property {boolean} soft
+ * @property {string} modelUrl - The URL of the model file. Models can be FBX or OBJ format.
+ * @property {string} jointName - The offset to apply to the model relative to the joint position.
+ * @property {Vec3} translation - The offset from the joint that the attachment is positioned at.
+ * @property {Vec3} rotation - The rotation applied to the model relative to the joint orientation.
+ * @property {number} scale - The scale applied to the attachment model.
+ * @property {boolean} soft - If true
and the model has a skeleton, the bones of the attached model's skeleton are
+ * rotated to fit the avatar's current pose. If true
, the translation
, rotation
, and
+ * scale
parameters are ignored.
*/
QVariant AttachmentData::toVariant() const {
QVariantMap result;
@@ -2942,6 +3015,10 @@ float AvatarData::_avatarSortCoefficientSize { 8.0f };
float AvatarData::_avatarSortCoefficientCenter { 0.25f };
float AvatarData::_avatarSortCoefficientAge { 1.0f };
+/**jsdoc
+ * An object with the UUIDs of avatar entities as keys and avatar entity properties objects as values.
+ * @typedef {Object.} AvatarEntityMap
+ */
QScriptValue AvatarEntityMapToScriptValue(QScriptEngine* engine, const AvatarEntityMap& value) {
QScriptValue obj = engine->newObject();
for (auto entityID : value.keys()) {
diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h
index 95bbcbeb16..00e7e67923 100755
--- a/libraries/avatars/src/AvatarData.h
+++ b/libraries/avatars/src/AvatarData.h
@@ -116,6 +116,24 @@ const int PROCEDURAL_BLINK_FACE_MOVEMENT = 10; // 11th bit
const int COLLIDE_WITH_OTHER_AVATARS = 11; // 12th bit
const int HAS_HERO_PRIORITY = 12; // 13th bit (be scared)
+/**jsdoc
+ * The pointing state of the hands is specified by the following values:
+
+ *
+ *
+ * Value Description
+ *
+ *
+ * 0
No hand is pointing.
+ * 1
The left hand is pointing.
+ * 2
The right hand is pointing.
+ * 4
It is the index finger that is pointing.
+ *
+ *
+ * The values for the hand states are added together to give the HandState
value. For example, if the left
+ * hand's finger is pointing, the value is 1 + 4 == 5
.
+ * @typedef {number} HandState
+ */
const char HAND_STATE_NULL = 0;
const char LEFT_HAND_POINTING_FLAG = 1;
const char RIGHT_HAND_POINTING_FLAG = 2;
@@ -414,7 +432,54 @@ class ClientTraitsHandler;
class AvatarData : public QObject, public SpatiallyNestable {
Q_OBJECT
- // The following properties have JSDoc in MyAvatar.h and ScriptableAvatar.h
+ // IMPORTANT: The JSDoc for the following properties should be copied to MyAvatar.h and ScriptableAvatar.h.
+ /*
+ * @property {Vec3} position - The position of the avatar.
+ * @property {number} scale=1.0 - The scale of the avatar. The value can be set to anything between 0.005
and
+ * 1000.0
. When the scale value is fetched, it may temporarily be further limited by the domain's settings.
+ * @property {number} density - The density of the avatar in kg/m3. The density is used to work out its mass in
+ * the application of physics. Read-only.
+ * @property {Vec3} handPosition - A user-defined hand position, in world coordinates. The position moves with the avatar
+ * but is otherwise not used or changed by Interface.
+ * @property {number} bodyYaw - The left or right rotation about an axis running from the head to the feet of the avatar.
+ * Yaw is sometimes called "heading".
+ * @property {number} bodyPitch - The rotation about an axis running from shoulder to shoulder of the avatar. Pitch is
+ * sometimes called "elevation".
+ * @property {number} bodyRoll - The rotation about an axis running from the chest to the back of the avatar. Roll is
+ * sometimes called "bank".
+ * @property {Quat} orientation - The orientation of the avatar.
+ * @property {Quat} headOrientation - The orientation of the avatar's head.
+ * @property {number} headPitch - The rotation about an axis running from ear to ear of the avatar's head. Pitch is
+ * sometimes called "elevation".
+ * @property {number} headYaw - The rotation left or right about an axis running from the base to the crown of the avatar's
+ * head. Yaw is sometimes called "heading".
+ * @property {number} headRoll - The rotation about an axis running from the nose to the back of the avatar's head. Roll is
+ * sometimes called "bank".
+ * @property {Vec3} velocity - The current velocity of the avatar.
+ * @property {Vec3} angularVelocity - The current angular velocity of the avatar.
+ * @property {number} audioLoudness - The instantaneous loudness of the audio input that the avatar is injecting into the
+ * domain.
+ * @property {number} audioAverageLoudness - The rolling average loudness of the audio input that the avatar is injecting
+ * into the domain.
+ * @property {string} displayName - The avatar's display name.
+ * @property {string} sessionDisplayName - displayName's
sanitized and default version defined by the avatar
+ * mixer rather than Interface clients. The result is unique among all avatars present in the domain at the time.
+ * @property {boolean} lookAtSnappingEnabled=true - true
if the avatar's eyes snap to look at another avatar's
+ * eyes when the other avatar is in the line of sight and also has lookAtSnappingEnabled == true
.
+ * @property {string} skeletonModelURL - The avatar's FST file.
+ * @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
+ * Deprecated: Use avatar entities instead.
+ * @property {string[]} jointNames - The list of joints in the current avatar model. Read-only.
+ * @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. Read-only.
+ * @property {Mat4} sensorToWorldMatrix - The scale, rotation, and translation transform from the user's real world to the
+ * avatar's size, orientation, and position in the virtual world. Read-only.
+ * @property {Mat4} controllerLeftHandMatrix - The rotation and translation of the left hand controller relative to the
+ * avatar. Read-only.
+ * @property {Mat4} controllerRightHandMatrix - The rotation and translation of the right hand controller relative to the
+ * avatar. Read-only.
+ * @property {number} sensorToWorldScale - The scale that transforms dimensions in the user's real world to the avatar's
+ * size in the virtual world. Read-only.
+ */
Q_PROPERTY(glm::vec3 position READ getWorldPosition WRITE setPositionViaScript)
Q_PROPERTY(float scale READ getDomainLimitedScale WRITE setTargetScale)
Q_PROPERTY(float density READ getDensity)
@@ -568,18 +633,18 @@ public:
virtual bool getHasAudioEnabledFaceMovement() const { return false; }
/**jsdoc
- * Returns the minimum scale allowed for this avatar in the current domain.
+ * Gets the minimum scale allowed for this avatar in the current domain.
* This value can change as the user changes avatars or when changing domains.
- * @function MyAvatar.getDomainMinScale
- * @returns {number} minimum scale allowed for this avatar in the current domain.
+ * @function Avatar.getDomainMinScale
+ * @returns {number} The minimum scale allowed for this avatar in the current domain.
*/
Q_INVOKABLE float getDomainMinScale() const;
/**jsdoc
- * Returns the maximum scale allowed for this avatar in the current domain.
+ * Gets the maximum scale allowed for this avatar in the current domain.
* This value can change as the user changes avatars or when changing domains.
- * @function MyAvatar.getDomainMaxScale
- * @returns {number} maximum scale allowed for this avatar in the current domain.
+ * @function Avatar.getDomainMaxScale
+ * @returns {number} The maximum scale allowed for this avatar in the current domain.
*/
Q_INVOKABLE float getDomainMaxScale() const;
@@ -592,18 +657,18 @@ public:
virtual bool canMeasureEyeHeight() const { return false; }
/**jsdoc
- * Provides read only access to the current eye height of the avatar.
+ * Gets the current eye height of the avatar.
* This height is only an estimate and might be incorrect for avatars that are missing standard joints.
- * @function MyAvatar.getEyeHeight
- * @returns {number} Eye height of avatar in meters.
+ * @function Avatar.getEyeHeight
+ * @returns {number} The eye height of the avatar.
*/
Q_INVOKABLE virtual float getEyeHeight() const { return _targetScale * getUnscaledEyeHeight(); }
/**jsdoc
- * Provides read only access to the current height of the avatar.
+ * Gets the current height of the avatar.
* This height is only an estimate and might be incorrect for avatars that are missing standard joints.
- * @function MyAvatar.getHeight
- * @returns {number} Height of avatar in meters.
+ * @function Avatar.getHeight
+ * @returns {number} The height of the avatar.
*/
Q_INVOKABLE virtual float getHeight() const;
@@ -613,36 +678,43 @@ public:
void setDomainMaximumHeight(float domainMaximumHeight);
/**jsdoc
- * @function MyAvatar.setHandState
- * @param {string} state
+ * Sets the pointing state of the hands to control where the laser emanates from. If the right index finger is pointing, the
+ * laser emanates from the tip of that finger, otherwise it emanates from the palm.
+ * @function Avatar.setHandState
+ * @param {HandState} state - The pointing state of the hand.
*/
Q_INVOKABLE void setHandState(char s) { _handState = s; }
/**jsdoc
- * @function MyAvatar.getHandState
- * @returns {string}
+ * Gets the pointing state of the hands to control where the laser emanates from. If the right index finger is pointing, the
+ * laser emanates from the tip of that finger, otherwise it emanates from the palm.
+ * @function Avatar.getHandState
+ * @returns {HandState} The pointing state of the hand.
*/
Q_INVOKABLE char getHandState() const { return _handState; }
const QVector& getRawJointData() const { return _jointData; }
/**jsdoc
- * @function MyAvatar.setRawJointData
- * @param {JointData[]} data
+ * Sets joint translations and rotations from raw joint data.
+ * @function Avatar.setRawJointData
+ * @param {JointData[]} data - The raw joint data.
+ * @deprecated This function is deprecated and will be removed.
*/
Q_INVOKABLE void setRawJointData(QVector data);
/**jsdoc
- * Set a specific joint's rotation and position relative to its parent.
- * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
+ * Sets a specific joint's rotation and position relative to its parent, in model coordinates.
+ *
Warning: These coordinates are not necessarily in meters.
+ * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
* kinematics, but just for the specified joint. So for example, if you were to procedurally manipulate the finger joints,
* the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate
* joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set
* the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.
- * @function MyAvatar.setJointData
+ * @function Avatar.setJointData
* @param {number} index - The index of the joint.
* @param {Quat} rotation - The rotation of the joint relative to its parent.
- * @param {Vec3} translation - The translation of the joint relative to its parent.
+ * @param {Vec3} translation - The translation of the joint relative to its parent, in model coordinates.
* @example Set your avatar to it's default T-pose for a while.
* 
* // Set all joint translations and rotations to defaults.
@@ -657,91 +729,98 @@ public:
* Script.setTimeout(function () {
* MyAvatar.clearJointsData();
* }, 5000);
+ *
+ * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation);
/**jsdoc
- * Set a specific joint's rotation relative to its parent.
+ * Sets a specific joint's rotation relative to its parent.
* Setting joint data completely overrides/replaces all motion from the default animation system including inverse
* kinematics, but just for the specified joint. So for example, if you were to procedurally manipulate the finger joints,
* the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate
* joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set
* the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.
- * @function MyAvatar.setJointRotation
+ * @function Avatar.setJointRotation
* @param {number} index - The index of the joint.
* @param {Quat} rotation - The rotation of the joint relative to its parent.
*/
Q_INVOKABLE virtual void setJointRotation(int index, const glm::quat& rotation);
/**jsdoc
- * Set a specific joint's translation relative to its parent.
- * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
+ * Sets a specific joint's translation relative to its parent, in model coordinates.
+ *
Warning: These coordinates are not necessarily in meters.
+ * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
* kinematics, but just for the specified joint. So for example, if you were to procedurally manipulate the finger joints,
* the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate
* joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set
* the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.
- * @function MyAvatar.setJointTranslation
+ * @function Avatar.setJointTranslation
* @param {number} index - The index of the joint.
- * @param {Vec3} translation - The translation of the joint relative to its parent.
+ * @param {Vec3} translation - The translation of the joint relative to its parent, in model coordinates.
*/
Q_INVOKABLE virtual void setJointTranslation(int index, const glm::vec3& translation);
/**jsdoc
- * Clear joint translations and rotations set by script for a specific joint. This restores all motion from the default
+ * Clears joint translations and rotations set by script for a specific joint. This restores all motion from the default
* animation system including inverse kinematics for that joint.
* Note: This is slightly faster than the function variation that specifies the joint name.
- * @function MyAvatar.clearJointData
+ * @function Avatar.clearJointData
* @param {number} index - The index of the joint.
*/
Q_INVOKABLE virtual void clearJointData(int index);
/**jsdoc
- * @function MyAvatar.isJointDataValid
- * @param {number} index
- * @returns {boolean}
+ * Checks that the data for a joint are valid.
+ * @function Avatar.isJointDataValid
+ * @param {number} index - The index of the joint.
+ * @returns {boolean} true
if the joint data are valid, false
if not.
*/
Q_INVOKABLE bool isJointDataValid(int index) const;
/**jsdoc
- * Get the rotation of a joint relative to its parent. For information on the joint hierarchy used, see
- * Avatar Standards.
- * @function MyAvatar.getJointRotation
+ * Gets the rotation of a joint relative to its parent. For information on the joint hierarchy used, see
+ * Avatar Standards.
+ * @function Avatar.getJointRotation
* @param {number} index - The index of the joint.
* @returns {Quat} The rotation of the joint relative to its parent.
*/
Q_INVOKABLE virtual glm::quat getJointRotation(int index) const;
/**jsdoc
- * Get the translation of a joint relative to its parent. For information on the joint hierarchy used, see
- * Avatar Standards.
- * @function MyAvatar.getJointTranslation
+ * Gets the translation of a joint relative to its parent, in model coordinates.
+ * Warning: These coordinates are not necessarily in meters.
+ * For information on the joint hierarchy used, see
+ * Avatar Standards.
+ * @function Avatar.getJointTranslation
* @param {number} index - The index of the joint.
- * @returns {Vec3} The translation of the joint relative to its parent.
+ * @returns {Vec3} The translation of the joint relative to its parent, in model coordinates.
*/
Q_INVOKABLE virtual glm::vec3 getJointTranslation(int index) const;
/**jsdoc
- * Set a specific joint's rotation and position relative to its parent.
- * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
+ * Sets a specific joint's rotation and position relative to its parent, in model coordinates.
+ *
Warning: These coordinates are not necessarily in meters.
+ * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
* kinematics, but just for the specified joint. So for example, if you were to procedurally manipulate the finger joints,
* the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate
* joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set
* the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.
- * @function MyAvatar.setJointData
+ * @function Avatar.setJointData
* @param {string} name - The name of the joint.
* @param {Quat} rotation - The rotation of the joint relative to its parent.
- * @param {Vec3} translation - The translation of the joint relative to its parent.
+ * @param {Vec3} translation - The translation of the joint relative to its parent, in model coordinates.
*/
Q_INVOKABLE virtual void setJointData(const QString& name, const glm::quat& rotation, const glm::vec3& translation);
/**jsdoc
- * Set a specific joint's rotation relative to its parent.
+ * Sets a specific joint's rotation relative to its parent.
* Setting joint data completely overrides/replaces all motion from the default animation system including inverse
* kinematics, but just for the specified joint. So for example, if you were to procedurally manipulate the finger joints,
* the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate
* joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set
* the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.
- * @function MyAvatar.setJointRotation
+ * @function Avatar.setJointRotation
* @param {string} name - The name of the joint.
* @param {Quat} rotation - The rotation of the joint relative to its parent.
* @example Set your avatar to its default T-pose then rotate its right arm.
@@ -762,104 +841,125 @@ public:
* Script.setTimeout(function () {
* MyAvatar.clearJointsData();
* }, 5000);
+ *
+ * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void setJointRotation(const QString& name, const glm::quat& rotation);
/**jsdoc
- * Set a specific joint's translation relative to its parent.
- * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
+ * Sets a specific joint's translation relative to its parent, in model coordinates.
+ *
Warning: These coordinates are not necessarily in meters.
+ * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
* kinematics, but just for the specified joint. So for example, if you were to procedurally manipulate the finger joints,
* the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate
* joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set
* the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.
- * @function MyAvatar.setJointTranslation
+ * @function Avatar.setJointTranslation
* @param {string} name - The name of the joint.
- * @param {Vec3} translation - The translation of the joint relative to its parent.
+ * @param {Vec3} translation - The translation of the joint relative to its parent, in model coordinates.
* @example Stretch your avatar's neck. Depending on the avatar you are using, you will either see a gap between
* the head and body or you will see the neck stretched.
* 
* // Stretch your avatar's neck.
- * MyAvatar.setJointTranslation("Neck", { x: 0, y: 25, z: 0 });
+ * MyAvatar.setJointTranslation("Neck", Vec3.multiply(2, MyAvatar.getJointTranslation("Neck")));
*
* // Restore your avatar's neck after 5s.
* Script.setTimeout(function () {
* MyAvatar.clearJointData("Neck");
* }, 5000);
+ *
+ * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void setJointTranslation(const QString& name, const glm::vec3& translation);
/**jsdoc
- * Clear joint translations and rotations set by script for a specific joint. This restores all motion from the default
+ * Clears joint translations and rotations set by script for a specific joint. This restores all motion from the default
* animation system including inverse kinematics for that joint.
* Note: This is slightly slower than the function variation that specifies the joint index.
- * @function MyAvatar.clearJointData
+ * @function Avatar.clearJointData
* @param {string} name - The name of the joint.
* @example Offset and restore the position of your avatar's head.
- * // Move your avatar's head up by 25cm from where it should be.
- * MyAvatar.setJointTranslation("Neck", { x: 0, y: 0.25, z: 0 });
+ * // Stretch your avatar's neck.
+ * MyAvatar.setJointTranslation("Neck", Vec3.multiply(2, MyAvatar.getJointTranslation("Neck")));
*
- * // Restore your avatar's head to its default position after 5s.
+ * // Restore your avatar's neck after 5s.
* Script.setTimeout(function () {
* MyAvatar.clearJointData("Neck");
* }, 5000);
+ *
+ * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void clearJointData(const QString& name);
/**jsdoc
- * @function MyAvatar.isJointDataValid
- * @param {string} name
- * @returns {boolean}
+ * Checks if the data for a joint are valid.
+ * @function Avatar.isJointDataValid
+ * @param {string} name - The name of the joint.
+ * @returns {boolean} true
if the joint data are valid, false
if not.
*/
Q_INVOKABLE virtual bool isJointDataValid(const QString& name) const;
/**jsdoc
- * Get the rotation of a joint relative to its parent. For information on the joint hierarchy used, see
- * Avatar Standards.
- * @function MyAvatar.getJointRotation
+ * Gets the rotation of a joint relative to its parent. For information on the joint hierarchy used, see
+ * Avatar Standards.
+ * @function Avatar.getJointRotation
* @param {string} name - The name of the joint.
* @returns {Quat} The rotation of the joint relative to its parent.
* @example Report the rotation of your avatar's hips joint.
* print(JSON.stringify(MyAvatar.getJointRotation("Hips")));
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual glm::quat getJointRotation(const QString& name) const;
/**jsdoc
- * Get the translation of a joint relative to its parent. For information on the joint hierarchy used, see
- * Avatar Standards.
- * @function MyAvatar.getJointTranslation
+ * Gets the translation of a joint relative to its parent, in model coordinates.
+ * Warning: These coordinates are not necessarily in meters.
+ * For information on the joint hierarchy used, see
+ * Avatar Standards.
+ * @function Avatar.getJointTranslation
* @param {number} name - The name of the joint.
- * @returns {Vec3} The translation of the joint relative to its parent.
+ * @returns {Vec3} The translation of the joint relative to its parent, in model coordinates.
* @example Report the translation of your avatar's hips joint.
* print(JSON.stringify(MyAvatar.getJointRotation("Hips")));
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual glm::vec3 getJointTranslation(const QString& name) const;
/**jsdoc
- * Get the rotations of all joints in the current avatar. Each joint's rotation is relative to its parent joint.
- * @function MyAvatar.getJointRotations
+ * Gets the rotations of all joints in the current avatar. Each joint's rotation is relative to its parent joint.
+ * @function Avatar.getJointRotations
* @returns {Quat[]} The rotations of all joints relative to each's parent. The values are in the same order as the array
- * returned by {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}.
+ * returned by {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the Avatar
API.
* @example Report the rotations of all your avatar's joints.
* print(JSON.stringify(MyAvatar.getJointRotations()));
+ *
+ * // Note: If using from the Avatar API, replace all "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual QVector getJointRotations() const;
/**jsdoc
- * @function MyAvatar.getJointTranslations
- * @returns {Vec3[]}
+ * Gets the translations of all joints in the current avatar. Each joint's translation is relative to its parent joint, in
+ * model coordinates.
+ * Warning: These coordinates are not necessarily in meters.
+ * @function Avatar.getJointTranslations
+ * @returns {Vec3[]} The translations of all joints relative to each's parent, in model coordinates. The values are in the
+ * same order as the array returned by {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the
+ * Avatar
API.
*/
Q_INVOKABLE virtual QVector getJointTranslations() const;
/**jsdoc
- * Set the rotations of all joints in the current avatar. Each joint's rotation is relative to its parent joint.
+ * Sets the rotations of all joints in the current avatar. Each joint's rotation is relative to its parent joint.
* Setting joint data completely overrides/replaces all motion from the default animation system including inverse
* kinematics, but just for the specified joint. So for example, if you were to procedurally manipulate the finger joints,
* the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate
* joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set
* the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.
- * @function MyAvatar.setJointRotations
+ * @function Avatar.setJointRotations
* @param {Quat[]} jointRotations - The rotations for all joints in the avatar. The values are in the same order as the
- * array returned by {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}.
+ * array returned by {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the Avatar
API.
* @example Set your avatar to its default T-pose then rotate its right arm.
* 
* // Set all joint translations and rotations to defaults.
@@ -883,19 +983,31 @@ public:
* Script.setTimeout(function () {
* MyAvatar.clearJointsData();
* }, 5000);
+ *
+ * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void setJointRotations(const QVector& jointRotations);
/**jsdoc
- * @function MyAvatar.setJointTranslations
- * @param {Vec3[]} translations
+ * Sets the translations of all joints in the current avatar. Each joint's translation is relative to its parent joint, in
+ * model coordinates.
+ * Warning: These coordinates are not necessarily in meters.
+ * Setting joint data completely overrides/replaces all motion from the default animation system including inverse
+ * kinematics, but just for the specified joint. So for example, if you were to procedurally manipulate the finger joints,
+ * the avatar's hand and head would still do inverse kinematics properly. However, as soon as you start to manipulate
+ * joints in the inverse kinematics chain, the inverse kinematics might not function as you expect. For example, if you set
+ * the rotation of the elbow, the hand inverse kinematics position won't end up in the right place.
+ * @function Avatar.setJointTranslations
+ * @param {Vec3[]} translations - The translations for all joints in the avatar, in model coordinates. The values are in
+ * the same order as the array returned by {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the
+ * Avatar
API.
*/
Q_INVOKABLE virtual void setJointTranslations(const QVector& jointTranslations);
/**jsdoc
- * Clear all joint translations and rotations that have been set by script. This restores all motion from the default
+ * Clears all joint translations and rotations that have been set by script. This restores all motion from the default
* animation system including inverse kinematics for all joints.
- * @function MyAvatar.clearJointsData
+ * @function Avatar.clearJointsData
* @example Set your avatar to it's default T-pose for a while.
* // Set all joint translations and rotations to defaults.
* var i, length, rotation, translation;
@@ -909,49 +1021,69 @@ public:
* Script.setTimeout(function () {
* MyAvatar.clearJointsData();
* }, 5000);
+ *
+ * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void clearJointsData();
/**jsdoc
- * Get the joint index for a named joint. The joint index value is the position of the joint in the array returned by
- * {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}.
- * @function MyAvatar.getJointIndex
+ * Gets the joint index for a named joint. The joint index value is the position of the joint in the array returned by
+ * {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the Avatar
API.
+ * @function Avatar.getJointIndex
* @param {string} name - The name of the joint.
- * @returns {number} The index of the joint.
+ * @returns {number} The index of the joint if valid, otherwise -1
.
* @example Report the index of your avatar's left arm joint.
- * print(JSON.stringify(MyAvatar.getJointIndex("LeftArm"));
+ * print(JSON.stringify(MyAvatar.getJointIndex("LeftArm")));
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
/// Returns the index of the joint with the specified name, or -1 if not found/unknown.
Q_INVOKABLE virtual int getJointIndex(const QString& name) const;
/**jsdoc
- * Get the names of all the joints in the current avatar.
- * @function MyAvatar.getJointNames
+ * Gets the names of all the joints in the current avatar.
+ * @function Avatar.getJointNames
* @returns {string[]} The joint names.
* @example Report the names of all the joints in your current avatar.
* print(JSON.stringify(MyAvatar.getJointNames()));
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual QStringList getJointNames() const;
/**jsdoc
- * @function MyAvatar.setBlendshape
- * @param {string} name
- * @param {number} value
+ * Sets the value of a blendshape to animate your avatar's face. To enable other users to see the resulting animation of
+ * your avatar's face, use {@link Avatar.setForceFaceTrackerConnected} or {@link MyAvatar.setForceFaceTrackerConnected}.
+ * @function Avatar.setBlendshape
+ * @param {string} name - The name of the blendshape, per the
+ * {@link https://docs.highfidelity.com/create/avatars/avatar-standards.html#blendshapes Avatar Standards}.
+ * @param {number} value - A value between 0.0
and 1.0
.
+ * @example Open your avatar's mouth wide.
+ * MyAvatar.setForceFaceTrackerConnected(true);
+ * MyAvatar.setBlendshape("JawOpen", 1.0);
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
Q_INVOKABLE void setBlendshape(QString name, float val) { _headData->setBlendshape(name, val); }
/**jsdoc
- * @function MyAvatar.getAttachmentsVariant
- * @returns {object}
+ * Gets information about the models currently attached to your avatar.
+ * @function Avatar.getAttachmentsVariant
+ * @returns {AttachmentData[]} Information about all models attached to your avatar.
+ * @deprecated Use avatar entities instead.
*/
// FIXME: Can this name be improved? Can it be deprecated?
Q_INVOKABLE virtual QVariantList getAttachmentsVariant() const;
/**jsdoc
- * @function MyAvatar.setAttachmentsVariant
- * @param {object} variant
+ * Sets all models currently attached to your avatar. For example, if you retrieve attachment data using
+ * {@link MyAvatar.getAttachmentsVariant} or {@link Avatar.getAttachmentsVariant}, make changes to it, and then want to
+ * update your avatar's attachments per the changed data.
+ * @function Avatar.setAttachmentsVariant
+ * @param {AttachmentData[]} variant - The attachment data defining the models to have attached to your avatar.
+ * @deprecated Use avatar entities instead.
*/
// FIXME: Can this name be improved? Can it be deprecated?
Q_INVOKABLE virtual void setAttachmentsVariant(const QVariantList& variant);
@@ -959,22 +1091,28 @@ public:
virtual void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload);
/**jsdoc
- * @function MyAvatar.updateAvatarEntity
- * @param {Uuid} entityID
- * @param {string} entityData
+ * @function Avatar.updateAvatarEntity
+ * @param {Uuid} entityID - The entity ID.
+ * @param {Array.} entityData - Entity data.
+ * @deprecated This function is deprecated and will be removed.
*/
Q_INVOKABLE virtual void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData);
/**jsdoc
- * @function MyAvatar.clearAvatarEntity
- * @param {Uuid} entityID
+ * @function Avatar.clearAvatarEntity
+ * @param {Uuid} entityID - The entity ID.
+ * @param {boolean} [requiresRemovalFromTree=true] - Requires removal from tree.
+ * @deprecated This function is deprecated and will be removed.
*/
Q_INVOKABLE virtual void clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree = true);
/**jsdoc
- * @function MyAvatar.setForceFaceTrackerConnected
- * @param {boolean} connected
+ * Enables blendshapes set using {@link Avatar.setBlendshape} or {@link MyAvatar.setBlendshape} to be transmitted to other
+ * users so that they can see the animation of your avatar's face.
+ * @function Avatar.setForceFaceTrackerConnected
+ * @param {boolean} connected - true
to enable blendshape changes to be transmitted to other users,
+ * false
to disable.
*/
Q_INVOKABLE void setForceFaceTrackerConnected(bool connected) { _forceFaceTrackerConnected = connected; }
@@ -1025,24 +1163,28 @@ public:
}
/**jsdoc
- * Get information about all models currently attached to your avatar.
- * @function MyAvatar.getAttachmentData
+ * Gets information about the models currently attached to your avatar.
+ * @function Avatar.getAttachmentData
* @returns {AttachmentData[]} Information about all models attached to your avatar.
+ * @deprecated Use avatar entities instead.
* @example Report the URLs of all current attachments.
* var attachments = MyAvatar.getaAttachmentData();
* for (var i = 0; i < attachments.length; i++) {
- * print (attachments[i].modelURL);
+ * print(attachments[i].modelURL);
* }
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual QVector getAttachmentData() const;
/**jsdoc
- * Set all models currently attached to your avatar. For example, if you retrieve attachment data using
+ * Sets all models currently attached to your avatar. For example, if you retrieve attachment data using
* {@link MyAvatar.getAttachmentData} or {@link Avatar.getAttachmentData}, make changes to it, and then want to update your avatar's attachments per the
* changed data. You can also remove all attachments by using setting attachmentData
to null
.
- * @function MyAvatar.setAttachmentData
- * @param {AttachmentData[]} attachmentData - The attachment data defining the models to have attached to your avatar. Use
+ * @function Avatar.setAttachmentData
+ * @param {AttachmentData[]} attachmentData - The attachment data defining the models to have attached to your avatar. Use
* null
to remove all attachments.
+ * @deprecated Use avatar entities instead.
* @example Remove a hat attachment if your avatar is wearing it.
* var hatURL = "https://s3.amazonaws.com/hifi-public/tony/cowboy-hat.fbx";
* var attachments = MyAvatar.getAttachmentData();
@@ -1054,15 +1196,17 @@ public:
* break;
* }
* }
+ *
+ * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void setAttachmentData(const QVector& attachmentData);
/**jsdoc
- * Attach a model to your avatar. For example, you can give your avatar a hat to wear, a guitar to hold, or a surfboard to
+ * Attaches a model to your avatar. For example, you can give your avatar a hat to wear, a guitar to hold, or a surfboard to
* stand on.
* Note: Attached models are models only; they are not entities and can not be manipulated using the {@link Entities} API.
* Nor can you use this function to attach an entity (such as a sphere or a box) to your avatar.
- * @function MyAvatar.attach
+ * @function Avatar.attach
* @param {string} modelURL - The URL of the model to attach. Models can be .FBX or .OBJ format.
* @param {string} [jointName=""] - The name of the avatar joint (see {@link MyAvatar.getJointNames} or {@link Avatar.getJointNames}) to attach the model
* to.
@@ -1070,12 +1214,14 @@ public:
* @param {Quat} [rotation=Quat.IDENTITY] - The rotation to apply to the model relative to the joint orientation.
* @param {number} [scale=1.0] - The scale to apply to the model.
* @param {boolean} [isSoft=false] - If the model has a skeleton, set this to true
so that the bones of the
- * attached model's skeleton are be rotated to fit the avatar's current pose. isSoft
is used, for example,
+ * attached model's skeleton are rotated to fit the avatar's current pose. isSoft
is used, for example,
* to have clothing that moves with the avatar.
* If true
, the translation
, rotation
, and scale
parameters are
* ignored.
- * @param {boolean} [allowDuplicates=false]
- * @param {boolean} [useSaved=true]
+ * @param {boolean} [allowDuplicates=false] - If true
then more than one copy of any particular model may be
+ * attached to the same joint; if false
then the same model cannot be attached to the same joint.
+ * @param {boolean} [useSaved=true] - Not used.
+ * @deprecated Use avatar entities instead.
* @example Attach a cowboy hat to your avatar's head.
* var attachment = {
* modelURL: "https://s3.amazonaws.com/hifi-public/tony/cowboy-hat.fbx",
@@ -1092,6 +1238,8 @@ public:
* attachment.rotation,
* attachment.scale,
* attachment.isSoft);
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void attach(const QString& modelURL, const QString& jointName = QString(),
const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(),
@@ -1099,20 +1247,22 @@ public:
bool allowDuplicates = false, bool useSaved = true);
/**jsdoc
- * Detach the most recently attached instance of a particular model from either a specific joint or any joint.
- * @function MyAvatar.detachOne
+ * Detaches the most recently attached instance of a particular model from either a specific joint or any joint.
+ * @function Avatar.detachOne
* @param {string} modelURL - The URL of the model to detach.
* @param {string} [jointName=""] - The name of the joint to detach the model from. If ""
, then the most
* recently attached model is removed from which ever joint it was attached to.
+ * @deprecated Use avatar entities instead.
*/
Q_INVOKABLE virtual void detachOne(const QString& modelURL, const QString& jointName = QString());
/**jsdoc
- * Detach all instances of a particular model from either a specific joint or all joints.
- * @function MyAvatar.detachAll
+ * Detaches all instances of a particular model from either a specific joint or all joints.
+ * @function Avatar.detachAll
* @param {string} modelURL - The URL of the model to detach.
* @param {string} [jointName=""] - The name of the joint to detach the model from. If ""
, then the model is
* detached from all joints.
+ * @deprecated Use avatar entities instead.
*/
Q_INVOKABLE virtual void detachAll(const QString& modelURL, const QString& jointName = QString());
@@ -1151,14 +1301,12 @@ public:
AABox getDefaultBubbleBox() const;
/**jsdoc
- * @function MyAvatar.getAvatarEntityData
- * @returns {object}
+ * @comment Documented in derived classes' JSDoc because implementations are different.
*/
Q_INVOKABLE virtual AvatarEntityMap getAvatarEntityData() const;
/**jsdoc
- * @function MyAvatar.setAvatarEntityData
- * @param {object} avatarEntityData
+ * @comment Documented in derived classes' JSDoc because implementations are different.
*/
Q_INVOKABLE virtual void setAvatarEntityData(const AvatarEntityMap& avatarEntityData);
@@ -1166,45 +1314,69 @@ public:
AvatarEntityIDs getAndClearRecentlyRemovedIDs();
/**jsdoc
- * @function MyAvatar.getSensorToWorldMatrix
- * @returns {Mat4}
+ * Gets the transform from the user's real world to the avatar's size, orientation, and position in the virtual world.
+ * @function Avatar.getSensorToWorldMatrix
+ * @returns {Mat4} The scale, rotation, and translation transform from the user's real world to the avatar's size,
+ * orientation, and position in the virtual world.
+ * @example Report the sensor to world matrix.
+ * var sensorToWorldMatrix = MyAvatar.getSensorToWorldMatrix();
+ * print("Sensor to woprld matrix: " + JSON.stringify(sensorToWorldMatrix));
+ * print("Rotation: " + JSON.stringify(Mat4.extractRotation(sensorToWorldMatrix)));
+ * print("Translation: " + JSON.stringify(Mat4.extractTranslation(sensorToWorldMatrix)));
+ * print("Scale: " + JSON.stringify(Mat4.extractScale(sensorToWorldMatrix)));
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
// thread safe
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
/**jsdoc
- * @function MyAvatar.getSensorToWorldScale
- * @returns {number}
+ * Gets the scale that transforms dimensions in the user's real world to the avatar's size in the virtual world.
+ * @function Avatar.getSensorToWorldScale
+ * @returns {number} The scale that transforms dimensions in the user's real world to the avatar's size in the virtual
+ * world.
*/
// thread safe
Q_INVOKABLE float getSensorToWorldScale() const;
/**jsdoc
- * @function MyAvatar.getControllerLeftHandMatrix
- * @returns {Mat4}
+ * Gets the rotation and translation of the left hand controller relative to the avatar.
+ * @function Avatar.getControllerLeftHandMatrix
+ * @returns {Mat4} The rotation and translation of the left hand controller relative to the avatar.
+ * @example Report the left hand controller matrix.
+ * var leftHandMatrix = MyAvatar.getControllerLeftHandMatrix();
+ * print("Controller left hand matrix: " + JSON.stringify(leftHandMatrix));
+ * print("Rotation: " + JSON.stringify(Mat4.extractRotation(leftHandMatrix)));
+ * print("Translation: " + JSON.stringify(Mat4.extractTranslation(leftHandMatrix)));
+ * print("Scale: " + JSON.stringify(Mat4.extractScale(leftHandMatrix))); // Always 1,1,1.
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
// thread safe
Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const;
/**jsdoc
- * @function MyAvatar.getControllerRightHandMatrix
- * @returns {Mat4}
+ * Gets the rotation and translation of the right hand controller relative to the avatar.
+ * @function Avatar.getControllerRightHandMatrix
+ * @returns {Mat4} The rotation and translation of the right hand controller relative to the avatar.
*/
// thread safe
Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const;
/**jsdoc
- * @function MyAvatar.getDataRate
- * @param {string} [rateName=""]
- * @returns {number}
+ * Gets the amount of avatar mixer data being generated by the avatar.
+ * @function Avatar.getDataRate
+ * @param {AvatarDataRate} [rateName=""] - The type of avatar mixer data to get the data rate of.
+ * @returns {number} The data rate in kbps.
*/
Q_INVOKABLE float getDataRate(const QString& rateName = QString("")) const;
/**jsdoc
- * @function MyAvatar.getUpdateRate
- * @param {string} [rateName=""]
- * @returns {number}
+ * Gets the update rate of avatar mixer data being generated by the avatar.
+ * @function Avatar.getUpdateRate
+ * @param {AvatarUpdateRate} [rateName=""] - The type of avatar mixer data to get the update rate of.
+ * @returns {number} The update rate in Hz.
*/
Q_INVOKABLE float getUpdateRate(const QString& rateName = QString("")) const;
@@ -1250,52 +1422,92 @@ public:
signals:
/**jsdoc
- * @function MyAvatar.displayNameChanged
+ * Triggered when the avatar's displayName
property value changes.
+ * @function Avatar.displayNameChanged
* @returns {Signal}
+ * @example Report when your avatar display name changes.
+ * MyAvatar.displayNameChanged.connect(function () {
+ * print("Avatar display name changed to: " + MyAvatar.displayName);
+ * });
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
void displayNameChanged();
/**jsdoc
- * @function MyAvatar.sessionDisplayNameChanged
+ * Triggered when the avatar's sessionDisplayName
property value changes.
+ * @function Avatar.sessionDisplayNameChanged
* @returns {Signal}
+ * @example Report when your avatar's session display name changes.
+ * MyAvatar.sessionDisplayNameChanged.connect(function () {
+ * print("Avatar session display name changed to: " + MyAvatar.sessionDisplayName);
+ * });
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
void sessionDisplayNameChanged();
/**jsdoc
- * @function MyAvatar.skeletonModelURLChanged
+ * Triggered when the avatar's model (i.e., skeletonModelURL
property value) is changed.
+ * @function Avatar.skeletonModelURLChanged
* @returns {Signal}
+ * @example Report when your avatar's skeleton model changes.
+ * MyAvatar.skeletonModelURLChanged.connect(function () {
+ * print("Skeleton model changed to: " + MyAvatar.skeletonModelURL);
+ * });
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
void skeletonModelURLChanged();
/**jsdoc
- * @function MyAvatar.lookAtSnappingChanged
- * @param {boolean} enabled
+ * Triggered when the avatar's lookAtSnappingEnabled
property value changes.
+ * @function Avatar.lookAtSnappingChanged
+ * @param {boolean} enabled - true
if look-at snapping is enabled, false
if not.
* @returns {Signal}
+ * @example Report when your look-at snapping setting changes.
+ * MyAvatar.lookAtSnappingChanged.connect(function () {
+ * print("Avatar look-at snapping changed to: " + MyAvatar.lookAtSnappingEnabled);
+ * });
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
void lookAtSnappingChanged(bool enabled);
/**jsdoc
- * @function MyAvatar.sessionUUIDChanged
+ * Triggered when the avatar's sessionUUID
property value changes.
+ * @function Avatar.sessionUUIDChanged
* @returns {Signal}
+ * @example Report when your avatar's session UUID changes.
+ * MyAvatar.sessionUUIDChanged.connect(function () {
+ * print("Avatar session UUID changed to: " + MyAvatar.sessionUUID);
+ * });
+ *
+ * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
void sessionUUIDChanged();
public slots:
/**jsdoc
- * @function MyAvatar.sendAvatarDataPacket
- * @param {boolean} [sendAll=false]
+ * @function Avatar.sendAvatarDataPacket
+ * @param {boolean} [sendAll=false] - Send all.
+ * @returns {number}
+ * @deprecated This function is deprecated and will be removed.
*/
virtual int sendAvatarDataPacket(bool sendAll = false);
/**jsdoc
- * @function MyAvatar.sendIdentityPacket
+ * @function Avatar.sendIdentityPacket
+ * @returns {number}
+ * @deprecated This function is deprecated and will be removed.
*/
int sendIdentityPacket();
/**jsdoc
- * @function MyAvatar.setSessionUUID
- * @param {Uuid} sessionUUID
+ * @function Avatar.setSessionUUID
+ * @param {Uuid} sessionUUID - Session UUID.
+ * @deprecated This function is deprecated and will be removed.
*/
virtual void setSessionUUID(const QUuid& sessionUUID) {
if (sessionUUID != getID()) {
@@ -1308,44 +1520,61 @@ public slots:
}
}
+
/**jsdoc
- * @function MyAvatar.getAbsoluteJointRotationInObjectFrame
- * @param {number} index
- * @returns {Quat}
+ * Gets the rotation of a joint relative to the avatar.
+ * Warning: Not able to be used in the Avatar
API.
+ * @function Avatar.getAbsoluteJointRotationInObjectFrame
+ * @param {number} index - The index of the joint. Not used.
+ * @returns {Quat} Quat.IDENTITY
.
*/
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
/**jsdoc
- * @function MyAvatar.getAbsoluteJointTranslationInObjectFrame
- * @param {number} index
- * @returns {Vec3}
+ * Gets the translation of a joint relative to the avatar.
+ * Warning: Not able to be used in the Avatar
API.
+ * @function Avatar.getAbsoluteJointTranslationInObjectFrame
+ * @param {number} index - The index of the joint. Not used.
+ * @returns {Vec3} Vec3.ZERO
.
*/
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
/**jsdoc
- * @function MyAvatar.setAbsoluteJointRotationInObjectFrame
- * @param {number} index
- * @param {Quat} rotation
- * @returns {boolean}
+ * Sets the rotation of a joint relative to the avatar.
+ * Warning: Not able to be used in the Avatar
API.
+ * @function Avatar.setAbsoluteJointRotationInObjectFrame
+ * @param {number} index - The index of the joint. Not used.
+ * @param {Quat} rotation - The rotation of the joint relative to the avatar. Not used.
+ * @returns {boolean} false
.
*/
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
/**jsdoc
- * @function MyAvatar.setAbsoluteJointTranslationInObjectFrame
- * @param {number} index
- * @param {Vec3} translation
- * @returns {boolean}
+ * Sets the translation of a joint relative to the avatar.
+ * Warning: Not able to be used in the Avatar
API.
+ * @function Avatar.setAbsoluteJointTranslationInObjectFrame
+ * @param {number} index - The index of the joint. Not used.
+ * @param {Vec3} translation - The translation of the joint relative to the avatar. Not used.
+ * @returns {boolean} false
.
*/
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
/**jsdoc
- * @function MyAvatar.getTargetScale
- * @returns {number}
+ * Gets the target scale of the avatar without any restrictions on permissible values imposed by the domain. In contrast, the
+ * scale
property's value may be limited by the domain's settings.
+ * @function Avatar.getTargetScale
+ * @returns {number} The target scale of the avatar.
+ * @example Compare the target and current avatar scales.
+ * print("Current avatar scale: " + MyAvatar.scale);
+ * print("Target avatar scale: " + MyAvatar.getTargetScale());
+ *
+ * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
float getTargetScale() const { return _targetScale; } // why is this a slot?
/**jsdoc
- * @function MyAvatar.resetLastSent
+ * @function Avatar.resetLastSent
+ * @deprecated This function is deprecated and will be removed.
*/
void resetLastSent() { _lastToByteArray = 0; }
diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
index 2eb877b0e1..b474fb2266 100644
--- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
@@ -169,7 +169,7 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
if (urlChanged && !usingMaterialData) {
_networkMaterial = MaterialCache::instance().getMaterial(_materialURL);
- auto onMaterialRequestFinished = [&, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
+ auto onMaterialRequestFinished = [this, oldParentID, oldParentMaterialName, newCurrentMaterialName](bool success) {
if (success) {
deleteMaterial(oldParentID, oldParentMaterialName);
_texturesLoaded = false;
@@ -186,7 +186,11 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
if (_networkMaterial->isLoaded()) {
onMaterialRequestFinished(!_networkMaterial->isFailed());
} else {
- connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished);
+ connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) {
+ withWriteLock([&] {
+ onMaterialRequestFinished(success);
+ });
+ });
}
}
} else if (materialDataChanged && usingMaterialData) {
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
index 98f79780be..2430643ce2 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
@@ -95,19 +95,18 @@ bool PolyLineEntityRenderer::needsRenderUpdate() const {
}
bool PolyLineEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
- return (
- entity->pointsChanged() ||
- entity->widthsChanged() ||
- entity->normalsChanged() ||
- entity->texturesChanged() ||
- entity->colorsChanged() ||
- _isUVModeStretch != entity->getIsUVModeStretch() ||
- _glow != entity->getGlow() ||
- _faceCamera != entity->getFaceCamera()
- );
+ if (entity->pointsChanged() || entity->widthsChanged() || entity->normalsChanged() || entity->texturesChanged() || entity->colorsChanged()) {
+ return true;
+ }
+
+ if (_isUVModeStretch != entity->getIsUVModeStretch() || _glow != entity->getGlow() || _faceCamera != entity->getFaceCamera()) {
+ return true;
+ }
+
+ return Parent::needsRenderUpdateFromTypedEntity(entity);
}
-void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
+void PolyLineEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
auto pointsChanged = entity->pointsChanged();
auto widthsChanged = entity->widthsChanged();
auto normalsChanged = entity->normalsChanged();
@@ -119,10 +118,6 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
entity->resetPolyLineChanged();
- // Transform
- updateModelTransformAndBound();
- _renderTransform = getModelTransform();
-
// Textures
if (entity->texturesChanged()) {
entity->resetTexturesChanged();
@@ -131,7 +126,9 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
if (!textures.isEmpty()) {
entityTextures = QUrl(textures);
}
- _texture = DependencyManager::get()->getTexture(entityTextures);
+ withWriteLock([&] {
+ _texture = DependencyManager::get()->getTexture(entityTextures);
+ });
_textureAspectRatio = 1.0f;
_textureLoaded = false;
}
@@ -145,11 +142,13 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
// Data
bool faceCameraChanged = faceCamera != _faceCamera;
- if (faceCameraChanged || glow != _glow) {
- _faceCamera = faceCamera;
- _glow = glow;
- updateData();
- }
+ withWriteLock([&] {
+ if (faceCameraChanged || glow != _glow) {
+ _faceCamera = faceCamera;
+ _glow = glow;
+ updateData();
+ }
+ });
// Geometry
if (pointsChanged) {
@@ -165,10 +164,23 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
_colors = entity->getStrokeColors();
_color = toGlm(entity->getColor());
}
- if (_isUVModeStretch != isUVModeStretch || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged) {
- _isUVModeStretch = isUVModeStretch;
- updateGeometry();
- }
+
+ bool uvModeStretchChanged = _isUVModeStretch != isUVModeStretch;
+ _isUVModeStretch = isUVModeStretch;
+
+ bool geometryChanged = uvModeStretchChanged || pointsChanged || widthsChanged || normalsChanged || colorsChanged || textureChanged || faceCameraChanged;
+
+ void* key = (void*)this;
+ AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, geometryChanged] () {
+ withWriteLock([&] {
+ updateModelTransformAndBound();
+ _renderTransform = getModelTransform();
+
+ if (geometryChanged) {
+ updateGeometry();
+ }
+ });
+ });
}
void PolyLineEntityRenderer::updateGeometry() {
@@ -267,22 +279,32 @@ void PolyLineEntityRenderer::updateData() {
}
void PolyLineEntityRenderer::doRender(RenderArgs* args) {
- if (_numVertices < 2) {
- return;
- }
-
PerformanceTimer perfTimer("RenderablePolyLineEntityItem::render");
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
- if (!_pipeline || !_glowPipeline) {
+ size_t numVertices;
+ Transform transform;
+ gpu::TexturePointer texture;
+ withReadLock([&] {
+ numVertices = _numVertices;
+ transform = _renderTransform;
+ texture = _textureLoaded ? _texture->getGPUTexture() : DependencyManager::get()->getWhiteTexture();
+
+ batch.setResourceBuffer(0, _polylineGeometryBuffer);
+ batch.setUniformBuffer(0, _polylineDataBuffer);
+ });
+
+ if (numVertices < 2) {
+ return;
+ }
+
+ if (!_pipeline) {
buildPipeline();
}
batch.setPipeline(_glow ? _glowPipeline : _pipeline);
- batch.setModelTransform(_renderTransform);
- batch.setResourceTexture(0, _textureLoaded ? _texture->getGPUTexture() : DependencyManager::get()->getWhiteTexture());
- batch.setResourceBuffer(0, _polylineGeometryBuffer);
- batch.setUniformBuffer(0, _polylineDataBuffer);
- batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * _numVertices), 0);
+ batch.setModelTransform(transform);
+ batch.setResourceTexture(0, texture);
+ batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * numVertices), 0);
}
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
index b8a3ad3b3e..3815b57671 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h
@@ -31,7 +31,7 @@ public:
protected:
virtual bool needsRenderUpdate() const override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
- virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
+ virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual ItemKey getKey() override;
virtual ShapeKey getShapeKey() override;
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
index b33eb619c8..33f4f2d751 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
@@ -249,10 +249,14 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
graphics::MultiMaterial materials;
auto geometryCache = DependencyManager::get();
GeometryCache::Shape geometryShape;
+ PrimitiveMode primitiveMode;
+ RenderLayer renderLayer;
bool proceduralRender = false;
glm::vec4 outColor;
withReadLock([&] {
geometryShape = geometryCache->getShapeForEntityShape(_shape);
+ primitiveMode = _primitiveMode;
+ renderLayer = _renderLayer;
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
materials = _materials["0"];
auto& schema = materials.getSchemaBuffer().get();
@@ -267,7 +271,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
});
if (proceduralRender) {
- if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
+ if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
geometryCache->renderWireShape(batch, geometryShape, outColor);
} else {
geometryCache->renderShape(batch, geometryShape, outColor);
@@ -275,10 +279,16 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
} else if (!useMaterialPipeline(materials)) {
// FIXME, support instanced multi-shape rendering using multidraw indirect
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
- if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
- geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, args->_shapePipeline);
+ render::ShapePipelinePointer pipeline;
+ if (renderLayer == RenderLayer::WORLD) {
+ pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
} else {
- geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, args->_shapePipeline);
+ pipeline = outColor.a < 1.0f ? geometryCache->getForwardTransparentShapePipeline() : geometryCache->getForwardOpaqueShapePipeline();
+ }
+ if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) {
+ geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline);
+ } else {
+ geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
}
} else {
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
index a3e1a2f56d..81f367a956 100644
--- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
@@ -162,10 +162,12 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
glm::vec4 backgroundColor;
Transform modelTransform;
glm::vec3 dimensions;
+ BillboardMode billboardMode;
bool layered;
withReadLock([&] {
modelTransform = _renderTransform;
dimensions = _dimensions;
+ billboardMode = _billboardMode;
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
textColor = glm::vec4(_textColor, fadeRatio * _textAlpha);
@@ -190,7 +192,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
}
auto transformToTopLeft = modelTransform;
- transformToTopLeft.setRotation(EntityItem::getBillboardRotation(transformToTopLeft.getTranslation(), transformToTopLeft.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
+ transformToTopLeft.setRotation(EntityItem::getBillboardRotation(transformToTopLeft.getTranslation(), transformToTopLeft.getRotation(), billboardMode, args->getViewFrustum().getPosition()));
transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed
@@ -210,10 +212,6 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
glm::vec2 bounds = glm::vec2(dimensions.x - (_leftMargin + _rightMargin), dimensions.y - (_topMargin + _bottomMargin));
_textRenderer->draw(batch, _leftMargin / scale, -_topMargin / scale, _text, textColor, bounds / scale, layered);
}
-
- if (layered) {
- DependencyManager::get()->unsetKeyLightBatch(batch);
- }
}
QSizeF TextEntityRenderer::textSize(const QString& text) const {
diff --git a/libraries/fbx/src/FBXSerializer.cpp b/libraries/fbx/src/FBXSerializer.cpp
index 5c5b5fa002..8da289806f 100644
--- a/libraries/fbx/src/FBXSerializer.cpp
+++ b/libraries/fbx/src/FBXSerializer.cpp
@@ -443,6 +443,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
QString hifiGlobalNodeID;
unsigned int meshIndex = 0;
haveReportedUnhandledRotationOrder = false;
+ int fbxVersionNumber = -1;
foreach (const FBXNode& child, node.children) {
if (child.name == "FBXHeaderExtension") {
@@ -465,6 +466,8 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
}
}
}
+ } else if (object.name == "FBXVersion") {
+ fbxVersionNumber = object.properties.at(0).toInt();
}
}
} else if (child.name == "GlobalSettings") {
@@ -1311,8 +1314,6 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
joint.bindTransformFoundInCluster = false;
- hfmModel.joints.append(joint);
-
QString rotationID = localRotations.value(modelID);
AnimationCurve xRotCurve = animationCurves.value(xComponents.value(rotationID));
AnimationCurve yRotCurve = animationCurves.value(yComponents.value(rotationID));
@@ -1335,7 +1336,13 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
xPosCurve.values.isEmpty() ? defaultPosValues.x : xPosCurve.values.at(i % xPosCurve.values.size()),
yPosCurve.values.isEmpty() ? defaultPosValues.y : yPosCurve.values.at(i % yPosCurve.values.size()),
zPosCurve.values.isEmpty() ? defaultPosValues.z : zPosCurve.values.at(i % zPosCurve.values.size()));
+ if ((fbxVersionNumber < 7500) && (i == 0)) {
+ joint.translation = hfmModel.animationFrames[i].translations[jointIndex];
+ joint.rotation = hfmModel.animationFrames[i].rotations[jointIndex];
+ }
+
}
+ hfmModel.joints.append(joint);
}
// NOTE: shapeVertices are in joint-frame
diff --git a/libraries/gpu/src/gpu/FrameReader.cpp b/libraries/gpu/src/gpu/FrameReader.cpp
index 2fe143ee90..812f4db7cc 100644
--- a/libraries/gpu/src/gpu/FrameReader.cpp
+++ b/libraries/gpu/src/gpu/FrameReader.cpp
@@ -40,7 +40,7 @@ public:
auto lastSlash = filename.rfind('/');
result = filename.substr(0, lastSlash + 1);
} else {
- std::string result = QFileInfo(filename.c_str()).absoluteDir().canonicalPath().toStdString();
+ result = QFileInfo(filename.c_str()).absoluteDir().canonicalPath().toStdString();
if (*result.rbegin() != '/') {
result += '/';
}
diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp
index e6eb6087b0..0021a594bc 100644
--- a/libraries/networking/src/NodeList.cpp
+++ b/libraries/networking/src/NodeList.cpp
@@ -1016,6 +1016,14 @@ void NodeList::maybeSendIgnoreSetToNode(SharedNodePointer newNode) {
// also send them the current ignore radius state.
sendIgnoreRadiusStateToNode(newNode);
+
+ // also send the current avatar and injector gains
+ if (_avatarGain != 0.0f) {
+ setAvatarGain(QUuid(), _avatarGain);
+ }
+ if (_injectorGain != 0.0f) {
+ setInjectorGain(_injectorGain);
+ }
}
if (newNode->getType() == NodeType::AvatarMixer) {
// this is a mixer that we just added - it's unlikely it knows who we were previously ignoring in this session,
@@ -1062,13 +1070,17 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) {
if (nodeID.isNull()) {
qCDebug(networking) << "Sending Set MASTER Avatar Gain packet with Gain:" << gain;
- } else {
- qCDebug(networking) << "Sending Set Avatar Gain packet with UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain;
- }
- sendPacket(std::move(setAvatarGainPacket), *audioMixer);
- QWriteLocker lock{ &_avatarGainMapLock };
- _avatarGainMap[nodeID] = gain;
+ sendPacket(std::move(setAvatarGainPacket), *audioMixer);
+ _avatarGain = gain;
+
+ } else {
+ qCDebug(networking) << "Sending Set Avatar Gain packet with UUID:" << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain;
+
+ sendPacket(std::move(setAvatarGainPacket), *audioMixer);
+ QWriteLocker lock{ &_avatarGainMapLock };
+ _avatarGainMap[nodeID] = gain;
+ }
} else {
qWarning() << "Couldn't find audio mixer to send set gain request";
@@ -1079,14 +1091,41 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) {
}
float NodeList::getAvatarGain(const QUuid& nodeID) {
- QReadLocker lock{ &_avatarGainMapLock };
- auto it = _avatarGainMap.find(nodeID);
- if (it != _avatarGainMap.cend()) {
- return it->second;
+ if (nodeID.isNull()) {
+ return _avatarGain;
+ } else {
+ QReadLocker lock{ &_avatarGainMapLock };
+ auto it = _avatarGainMap.find(nodeID);
+ if (it != _avatarGainMap.cend()) {
+ return it->second;
+ }
}
return 0.0f;
}
+void NodeList::setInjectorGain(float gain) {
+ auto audioMixer = soloNodeOfType(NodeType::AudioMixer);
+ if (audioMixer) {
+ // setup the packet
+ auto setInjectorGainPacket = NLPacket::create(PacketType::InjectorGainSet, sizeof(float), true);
+
+ // We need to convert the gain in dB (from the script) to an amplitude before packing it.
+ setInjectorGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.02059991f)));
+
+ qCDebug(networking) << "Sending Set Injector Gain packet with Gain:" << gain;
+
+ sendPacket(std::move(setInjectorGainPacket), *audioMixer);
+ _injectorGain = gain;
+
+ } else {
+ qWarning() << "Couldn't find audio mixer to send set gain request";
+ }
+}
+
+float NodeList::getInjectorGain() {
+ return _injectorGain;
+}
+
void NodeList::kickNodeBySessionID(const QUuid& nodeID) {
// send a request to domain-server to kick the node with the given session ID
// the domain-server will handle the persistence of the kick (via username or IP)
diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h
index e135bc937d..f871560fba 100644
--- a/libraries/networking/src/NodeList.h
+++ b/libraries/networking/src/NodeList.h
@@ -83,6 +83,8 @@ public:
bool isPersonalMutingNode(const QUuid& nodeID) const;
void setAvatarGain(const QUuid& nodeID, float gain);
float getAvatarGain(const QUuid& nodeID);
+ void setInjectorGain(float gain);
+ float getInjectorGain();
void kickNodeBySessionID(const QUuid& nodeID);
void muteNodeBySessionID(const QUuid& nodeID);
@@ -181,6 +183,9 @@ private:
mutable QReadWriteLock _avatarGainMapLock;
tbb::concurrent_unordered_map _avatarGainMap;
+ std::atomic _avatarGain { 0.0f }; // in dB
+ std::atomic _injectorGain { 0.0f }; // in dB
+
void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode);
#if defined(Q_OS_ANDROID)
Setting::Handle _ignoreRadiusEnabled { "IgnoreRadiusEnabled", false };
diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h
index 0ec7c40ca4..413ff14b17 100644
--- a/libraries/networking/src/udt/PacketHeaders.h
+++ b/libraries/networking/src/udt/PacketHeaders.h
@@ -57,7 +57,7 @@ public:
ICEServerQuery,
OctreeStats,
SetAvatarTraits,
- UNUSED_PACKET_TYPE,
+ InjectorGainSet,
AssignmentClientStatus,
NoisyMute,
AvatarIdentity,
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index 6ec69b5e20..7cad337dd5 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -178,7 +178,6 @@ void CauterizedModel::updateClusterMatrices() {
}
}
}
- computeMeshPartLocalBounds();
// post the blender if we're not currently waiting for one to finish
auto modelBlender = DependencyManager::get();
diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp
index c189798a42..2e762a0107 100644
--- a/libraries/render-utils/src/GeometryCache.cpp
+++ b/libraries/render-utils/src/GeometryCache.cpp
@@ -722,6 +722,8 @@ gpu::ShaderPointer GeometryCache::_unlitFadeShader;
render::ShapePipelinePointer GeometryCache::_simpleOpaquePipeline;
render::ShapePipelinePointer GeometryCache::_simpleTransparentPipeline;
+render::ShapePipelinePointer GeometryCache::_forwardSimpleOpaquePipeline;
+render::ShapePipelinePointer GeometryCache::_forwardSimpleTransparentPipeline;
render::ShapePipelinePointer GeometryCache::_simpleOpaqueFadePipeline;
render::ShapePipelinePointer GeometryCache::_simpleTransparentFadePipeline;
render::ShapePipelinePointer GeometryCache::_simpleWirePipeline;
@@ -801,6 +803,8 @@ void GeometryCache::initializeShapePipelines() {
if (!_simpleOpaquePipeline) {
_simpleOpaquePipeline = getShapePipeline(false, false, true, false);
_simpleTransparentPipeline = getShapePipeline(false, true, true, false);
+ _forwardSimpleOpaquePipeline = getShapePipeline(false, false, true, false, false, true);
+ _forwardSimpleTransparentPipeline = getShapePipeline(false, true, true, false, false, true);
_simpleOpaqueFadePipeline = getFadingShapePipeline(false, false, false, false, false);
_simpleTransparentFadePipeline = getFadingShapePipeline(false, true, false, false, false);
_simpleWirePipeline = getShapePipeline(false, false, true, true);
diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h
index cd3454bf38..4ff061786a 100644
--- a/libraries/render-utils/src/GeometryCache.h
+++ b/libraries/render-utils/src/GeometryCache.h
@@ -181,6 +181,11 @@ public:
static void initializeShapePipelines();
+ render::ShapePipelinePointer getOpaqueShapePipeline() { assert(_simpleOpaquePipeline != nullptr); return _simpleOpaquePipeline; }
+ render::ShapePipelinePointer getTransparentShapePipeline() { assert(_simpleTransparentPipeline != nullptr); return _simpleTransparentPipeline; }
+ render::ShapePipelinePointer getForwardOpaqueShapePipeline() { assert(_forwardSimpleOpaquePipeline != nullptr); return _forwardSimpleOpaquePipeline; }
+ render::ShapePipelinePointer getForwardTransparentShapePipeline() { assert(_forwardSimpleTransparentPipeline != nullptr); return _forwardSimpleTransparentPipeline; }
+
// Static (instanced) geometry
void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer);
@@ -368,6 +373,7 @@ public:
const ShapeData * getShapeData(Shape shape) const;
graphics::MeshPointer meshFromShape(Shape geometryShape, glm::vec3 color);
+
private:
GeometryCache();
@@ -461,6 +467,8 @@ private:
static gpu::ShaderPointer _unlitFadeShader;
static render::ShapePipelinePointer _simpleOpaquePipeline;
static render::ShapePipelinePointer _simpleTransparentPipeline;
+ static render::ShapePipelinePointer _forwardSimpleOpaquePipeline;
+ static render::ShapePipelinePointer _forwardSimpleTransparentPipeline;
static render::ShapePipelinePointer _simpleOpaqueFadePipeline;
static render::ShapePipelinePointer _simpleTransparentFadePipeline;
static render::ShapePipelinePointer _simpleWirePipeline;
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 30c4000bc7..89a9c7cf47 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -1346,19 +1346,14 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) {
}
void Model::computeMeshPartLocalBounds() {
- render::Transaction transaction;
- auto meshStates = _meshStates;
- for (auto renderItem : _modelMeshRenderItemIDs) {
- transaction.updateItem(renderItem, [this, meshStates](ModelMeshPartPayload& data) {
- const Model::MeshState& state = meshStates.at(data._meshIndex);
- if (_useDualQuaternionSkinning) {
- data.computeAdjustedLocalBound(state.clusterDualQuaternions);
- } else {
- data.computeAdjustedLocalBound(state.clusterMatrices);
- }
- });
+ for (auto& part : _modelMeshRenderItems) {
+ const Model::MeshState& state = _meshStates.at(part->_meshIndex);
+ if (_useDualQuaternionSkinning) {
+ part->computeAdjustedLocalBound(state.clusterDualQuaternions);
+ } else {
+ part->computeAdjustedLocalBound(state.clusterMatrices);
+ }
}
- AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
}
// virtual
@@ -1391,7 +1386,6 @@ void Model::updateClusterMatrices() {
}
}
}
- computeMeshPartLocalBounds();
// post the blender if we're not currently waiting for one to finish
auto modelBlender = DependencyManager::get();
@@ -1648,7 +1642,7 @@ using packBlendshapeOffsetTo = void(glm::uvec4& packed, const BlendshapeOffsetUn
void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& packed, const BlendshapeOffsetUnpacked& unpacked) {
float len = glm::compMax(glm::abs(unpacked.positionOffset));
glm::vec3 normalizedPos(unpacked.positionOffset);
- if (len > 1.0f) {
+ if (len > 0.0f) {
normalizedPos /= len;
} else {
len = 1.0f;
diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp
index e77ccb74a5..e021465ff3 100644
--- a/libraries/render-utils/src/RenderCommonTask.cpp
+++ b/libraries/render-utils/src/RenderCommonTask.cpp
@@ -95,7 +95,11 @@ void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs&
// Setup lighting model for all items;
batch.setUniformBuffer(ru::Buffer::LightModel, lightingModel->getParametersBuffer());
- renderShapes(renderContext, _shapePlumber, inItems, _maxDrawn);
+ if (_opaquePass) {
+ renderStateSortShapes(renderContext, _shapePlumber, inItems, _maxDrawn);
+ } else {
+ renderShapes(renderContext, _shapePlumber, inItems, _maxDrawn);
+ }
args->_batch = nullptr;
});
}
diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp
index 089d267711..ea2b05a6fa 100644
--- a/libraries/render-utils/src/RenderDeferredTask.cpp
+++ b/libraries/render-utils/src/RenderDeferredTask.cpp
@@ -216,8 +216,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob("DrawHazeDeferred", drawHazeInputs);
// Render transparent objects forward in LightingBuffer
- const auto transparentsInputs = DrawDeferred::Inputs(transparents, hazeFrame, lightFrame, lightingModel, lightClusters, shadowFrame, jitter).asVarying();
- task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber);
+ const auto transparentsInputs = RenderTransparentDeferred::Inputs(transparents, hazeFrame, lightFrame, lightingModel, lightClusters, shadowFrame, jitter).asVarying();
+ task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber);
const auto outlineRangeTimer = task.addJob("BeginHighlightRangeTimer", "Highlight");
@@ -436,7 +436,7 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input
}
-void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
+void RenderTransparentDeferred::run(const RenderContextPointer& renderContext, const Inputs& inputs) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
@@ -453,7 +453,7 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs&
RenderArgs* args = renderContext->args;
- gpu::doInBatch("DrawDeferred::run", args->_context, [&](gpu::Batch& batch) {
+ gpu::doInBatch("RenderTransparentDeferred::run", args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
// Setup camera, projection and viewport for all items
diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h
index 0a188ec3a6..3eb1153928 100644
--- a/libraries/render-utils/src/RenderDeferredTask.h
+++ b/libraries/render-utils/src/RenderDeferredTask.h
@@ -19,7 +19,7 @@
#include "LightClusters.h"
#include "RenderShadowTask.h"
-class DrawDeferredConfig : public render::Job::Config {
+class RenderTransparentDeferredConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY newStats)
Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty)
@@ -41,13 +41,13 @@ protected:
int _numDrawn{ 0 };
};
-class DrawDeferred {
+class RenderTransparentDeferred {
public:
using Inputs = render::VaryingSet7;
- using Config = DrawDeferredConfig;
- using JobModel = render::Job::ModelI;
+ using Config = RenderTransparentDeferredConfig;
+ using JobModel = render::Job::ModelI;
- DrawDeferred(render::ShapePlumberPointer shapePlumber)
+ RenderTransparentDeferred(render::ShapePlumberPointer shapePlumber)
: _shapePlumber{ shapePlumber } {}
void configure(const Config& config) { _maxDrawn = config.maxDrawn; }
diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp
index 73692b41c2..0bc117bdb9 100755
--- a/libraries/render-utils/src/RenderForwardTask.cpp
+++ b/libraries/render-utils/src/RenderForwardTask.cpp
@@ -98,7 +98,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
// Draw opaques forward
const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel).asVarying();
- task.addJob("DrawOpaques", opaqueInputs, shapePlumber);
+ task.addJob("DrawOpaques", opaqueInputs, shapePlumber, true);
// Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job
const auto backgroundInputs = DrawBackgroundStage::Inputs(lightingModel, backgroundFrame).asVarying();
@@ -106,7 +106,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
// Draw transparent objects forward
const auto transparentInputs = DrawForward::Inputs(transparents, lightingModel).asVarying();
- task.addJob("DrawTransparents", transparentInputs, shapePlumber);
+ task.addJob("DrawTransparents", transparentInputs, shapePlumber, false);
// Layered
const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f));
@@ -261,7 +261,11 @@ void DrawForward::run(const RenderContextPointer& renderContext, const Inputs& i
args->_globalShapeKey = globalKey._flags.to_ulong();
// Render items
- renderStateSortShapes(renderContext, _shapePlumber, inItems, -1, globalKey);
+ if (_opaquePass) {
+ renderStateSortShapes(renderContext, _shapePlumber, inItems, -1, globalKey);
+ } else {
+ renderShapes(renderContext, _shapePlumber, inItems, -1, globalKey);
+ }
args->_batch = nullptr;
args->_globalShapeKey = 0;
diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h
index 85b51ad5fa..40d004ddb2 100755
--- a/libraries/render-utils/src/RenderForwardTask.h
+++ b/libraries/render-utils/src/RenderForwardTask.h
@@ -76,12 +76,13 @@ public:
using Inputs = render::VaryingSet2;
using JobModel = render::Job::ModelI;
- DrawForward(const render::ShapePlumberPointer& shapePlumber) : _shapePlumber(shapePlumber) {}
+ DrawForward(const render::ShapePlumberPointer& shapePlumber, bool opaquePass) : _shapePlumber(shapePlumber), _opaquePass(opaquePass) {}
void run(const render::RenderContextPointer& renderContext,
const Inputs& inputs);
private:
render::ShapePlumberPointer _shapePlumber;
+ bool _opaquePass;
};
#endif // hifi_RenderForwardTask_h
diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf
index f1bb2b1ea2..9f8a88c7c2 100644
--- a/libraries/render-utils/src/simple_transparent_textured.slf
+++ b/libraries/render-utils/src/simple_transparent_textured.slf
@@ -16,8 +16,8 @@
<@include gpu/Color.slh@>
<@include render-utils/ShaderConstants.h@>
-<@include ForwardGlobalLight.slh@>
-<$declareEvalGlobalLightingAlphaBlended()$>
+<@include DeferredGlobalLight.slh@>
+<$declareEvalGlobalLightingAlphaBlendedWithHaze()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
diff --git a/libraries/script-engine/src/Mat4.h b/libraries/script-engine/src/Mat4.h
index 7ad77b9b24..0cdc70e79c 100644
--- a/libraries/script-engine/src/Mat4.h
+++ b/libraries/script-engine/src/Mat4.h
@@ -23,6 +23,7 @@
/**jsdoc
* @namespace Mat4
+ * @variation 0
*
* @hifi-interface
* @hifi-client-entity
@@ -38,7 +39,7 @@ class Mat4 : public QObject, protected QScriptable {
public slots:
/**jsdoc
- * @function Mat4.multiply
+ * @function Mat4(0).multiply
* @param {Mat4} m1
* @param {Mat4} m2
* @returns {Mat4}
@@ -47,7 +48,7 @@ public slots:
/**jsdoc
- * @function Mat4.createFromRotAndTrans
+ * @function Mat4(0).createFromRotAndTrans
* @param {Quat} rot
* @param {Vec3} trans
* @returns {Mat4}
@@ -55,7 +56,7 @@ public slots:
glm::mat4 createFromRotAndTrans(const glm::quat& rot, const glm::vec3& trans) const;
/**jsdoc
- * @function Mat4.createFromScaleRotAndTrans
+ * @function Mat4(0).createFromScaleRotAndTrans
* @param {Vec3} scale
* @param {Quat} rot
* @param {Vec3} trans
@@ -64,7 +65,7 @@ public slots:
glm::mat4 createFromScaleRotAndTrans(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) const;
/**jsdoc
- * @function Mat4.createFromColumns
+ * @function Mat4(0).createFromColumns
* @param {Vec4} col0
* @param {Vec4} col1
* @param {Vec4} col2
@@ -74,7 +75,7 @@ public slots:
glm::mat4 createFromColumns(const glm::vec4& col0, const glm::vec4& col1, const glm::vec4& col2, const glm::vec4& col3) const;
/**jsdoc
- * @function Mat4.createFromArray
+ * @function Mat4(0).createFromArray
* @param {number[]} numbers
* @returns {Mat4}
*/
@@ -82,21 +83,21 @@ public slots:
/**jsdoc
- * @function Mat4.extractTranslation
+ * @function Mat4(0).extractTranslation
* @param {Mat4} m
* @returns {Vec3}
*/
glm::vec3 extractTranslation(const glm::mat4& m) const;
/**jsdoc
- * @function Mat4.extractRotation
+ * @function Mat4(0).extractRotation
* @param {Mat4} m
* @returns {Vec3}
*/
glm::quat extractRotation(const glm::mat4& m) const;
/**jsdoc
- * @function Mat4.extractScale
+ * @function Mat4(0).extractScale
* @param {Mat4} m
* @returns {Vec3}
*/
@@ -104,7 +105,7 @@ public slots:
/**jsdoc
- * @function Mat4.transformPoint
+ * @function Mat4(0).transformPoint
* @param {Mat4} m
* @param {Vec3} point
* @returns {Vec3}
@@ -112,7 +113,7 @@ public slots:
glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& point) const;
/**jsdoc
- * @function Mat4.transformVector
+ * @function Mat4(0).transformVector
* @param {Mat4} m
* @param {Vec3} vector
* @returns {Vec3}
@@ -121,7 +122,7 @@ public slots:
/**jsdoc
- * @function Mat4.inverse
+ * @function Mat4(0).inverse
* @param {Mat4} m
* @returns {Mat4}
*/
@@ -129,7 +130,7 @@ public slots:
/**jsdoc
- * @function Mat4.getFront
+ * @function Mat4(0).getFront
* @param {Mat4} m
* @returns {Vec3}
*/
@@ -137,28 +138,28 @@ public slots:
glm::vec3 getFront(const glm::mat4& m) const { return getForward(m); }
/**jsdoc
- * @function Mat4.getForward
+ * @function Mat4(0).getForward
* @param {Mat4} m
* @returns {Vec3}
*/
glm::vec3 getForward(const glm::mat4& m) const;
/**jsdoc
- * @function Mat4.getRight
+ * @function Mat4(0).getRight
* @param {Mat4} m
* @returns {Vec3}
*/
glm::vec3 getRight(const glm::mat4& m) const;
/**jsdoc
- * @function Mat4.getUp
+ * @function Mat4(0).getUp
* @param {Mat4} m
* @returns {Vec3}
*/
glm::vec3 getUp(const glm::mat4& m) const;
/**jsdoc
- * @function Mat4.print
+ * @function Mat4(0).print
* @param {string} label
* @param {Mat4} m
* @param {boolean} [transpose=false]
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 48fb4f0b83..3549578ed5 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -573,11 +573,12 @@ public slots:
/**jsdoc
* @function Script.callAnimationStateHandler
- * @param {function} callback
- * @param {object} parameters
- * @param {string[]} names
- * @param {boolean} useNames
- * @param {object} resultHandler
+ * @param {function} callback - Callback.
+ * @param {object} parameters - Parameters.
+ * @param {string[]} names - Names.
+ * @param {boolean} useNames - Use names.
+ * @param {function} resultHandler - Result handler.
+ * @deprecated This function is deprecated and will be removed.
*/
void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler);
diff --git a/libraries/shared/src/BillboardMode.h b/libraries/shared/src/BillboardMode.h
index 050f939941..700127aff1 100644
--- a/libraries/shared/src/BillboardMode.h
+++ b/libraries/shared/src/BillboardMode.h
@@ -18,9 +18,11 @@
* Value Description
*
*
- * none
The entity will not be billboarded.
- * yaw
The entity will yaw, but not pitch, to face the camera. Its actual rotation will be ignored.
- * full
The entity will be billboarded to face the camera. Its actual rotation will be ignored.
+ * "none"
The entity will not be billboarded.
+ * "yaw"
The entity will yaw, but not pitch, to face the camera. Its actual rotation will be
+ * ignored.
+ * "full"
The entity will be billboarded to face the camera. Its actual rotation will be
+ * ignored.
*
*
* @typedef {string} BillboardMode
diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp
index 47549b639a..597e537d8d 100644
--- a/libraries/shared/src/RegisteredMetaTypes.cpp
+++ b/libraries/shared/src/RegisteredMetaTypes.cpp
@@ -1069,13 +1069,14 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) {
}
/**jsdoc
+ * Details of a collision between avatars and entities.
* @typedef {object} Collision
* @property {ContactEventType} type - The contact type of the collision event.
- * @property {Uuid} idA - The ID of one of the entities in the collision.
- * @property {Uuid} idB - The ID of the other of the entities in the collision.
- * @property {Vec3} penetration - The amount of penetration between the two entities.
+ * @property {Uuid} idA - The ID of one of the avatars or entities in the collision.
+ * @property {Uuid} idB - The ID of the other of the avatars or entities in the collision.
+ * @property {Vec3} penetration - The amount of penetration between the two items.
* @property {Vec3} contactPoint - The point of contact.
- * @property {Vec3} velocityChange - The change in relative velocity of the two entities, in m/s.
+ * @property {Vec3} velocityChange - The change in relative velocity of the two items, in m/s.
*/
QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision) {
QScriptValue obj = engine->newObject();
@@ -1147,19 +1148,21 @@ AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float prio
}
/**jsdoc
+ * The details of an animation that is playing.
* @typedef {object} Avatar.AnimationDetails
- * @property {string} role
- * @property {string} url
- * @property {number} fps
- * @property {number} priority
- * @property {boolean} loop
- * @property {boolean} hold
- * @property {boolean} startAutomatically
- * @property {number} firstFrame
- * @property {number} lastFrame
- * @property {boolean} running
- * @property {number} currentFrame
- * @property {boolean} allowTranslation
+ * @property {string} role - Not used.
+ * @property {string} url - The URL to the animation file. Animation files need to be in .FBX format but only need to contain
+* the avatar skeleton and animation data.
+ * @property {number} fps - The frames per second(FPS) rate for the animation playback. 30 FPS is normal speed.
+ * @property {number} priority - Not used.
+ * @property {boolean} loop - true
if the animation should loop, false
if it shouldn't.
+ * @property {boolean} hold - Not used.
+ * @property {number} firstFrame - The frame the animation should start at.
+ * @property {number} lastFrame - The frame the animation should stop at.
+ * @property {boolean} running - Not used.
+ * @property {number} currentFrame - The current frame being played.
+ * @property {boolean} startAutomatically - Not used.
+ * @property {boolean} allowTranslation - Not used.
*/
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& details) {
QScriptValue obj = engine->newObject();
diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h
index 1edb303455..ea2c5b8354 100644
--- a/libraries/shared/src/RegisteredMetaTypes.h
+++ b/libraries/shared/src/RegisteredMetaTypes.h
@@ -43,6 +43,27 @@ Q_DECLARE_METATYPE(std::function);
void registerMetaTypes(QScriptEngine* engine);
// Mat4
+/**jsdoc
+ * A 4 x 4 matrix, typically containing a scale, rotation, and translation transform. See also the {@link Mat4(0)|Mat4} object.
+ *
+ * @typedef {object} Mat4
+ * @property {number} r0c0 - Row 0, column 0 value.
+ * @property {number} r1c0 - Row 1, column 0 value.
+ * @property {number} r2c0 - Row 2, column 0 value.
+ * @property {number} r3c0 - Row 3, column 0 value.
+ * @property {number} r0c1 - Row 0, column 1 value.
+ * @property {number} r1c1 - Row 1, column 1 value.
+ * @property {number} r2c1 - Row 2, column 1 value.
+ * @property {number} r3c1 - Row 3, column 1 value.
+ * @property {number} r0c2 - Row 0, column 2 value.
+ * @property {number} r1c2 - Row 1, column 2 value.
+ * @property {number} r2c2 - Row 2, column 2 value.
+ * @property {number} r3c2 - Row 3, column 2 value.
+ * @property {number} r0c3 - Row 0, column 3 value.
+ * @property {number} r1c3 - Row 1, column 3 value.
+ * @property {number} r2c3 - Row 2, column 3 value.
+ * @property {number} r3c3 - Row 3, column 3 value.
+ */
QScriptValue mat4toScriptValue(QScriptEngine* engine, const glm::mat4& mat4);
void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4);
diff --git a/libraries/shared/src/shared/Camera.h b/libraries/shared/src/shared/Camera.h
index 31e6228bb9..0132e58d18 100644
--- a/libraries/shared/src/shared/Camera.h
+++ b/libraries/shared/src/shared/Camera.h
@@ -138,7 +138,7 @@ public slots:
* var pickRay = Camera.computePickRay(event.x, event.y);
* var intersection = Entities.findRayIntersection(pickRay);
* if (intersection.intersects) {
- * print ("You clicked on entity " + intersection.entityID);
+ * print("You clicked on entity " + intersection.entityID);
* }
* }
*
diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js
index 17ff918243..86806fd8b4 100644
--- a/scripts/system/commerce/wallet.js
+++ b/scripts/system/commerce/wallet.js
@@ -377,6 +377,9 @@ function deleteSendMoneyParticleEffect() {
}
function onUsernameChanged() {
+ if (ui.checkIsOpen()) {
+ ui.open(WALLET_QML_SOURCE);
+ }
}
var MARKETPLACE_QML_PATH = "hifi/commerce/marketplace/Marketplace.qml";
diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js
index f4c0cbb0d6..0a9fa4dce1 100644
--- a/scripts/system/controllers/controllerDispatcher.js
+++ b/scripts/system/controllers/controllerDispatcher.js
@@ -12,7 +12,7 @@
LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES,
getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers,
PointerManager, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Picks, PickType, Pointers,
- PointerManager, print, Selection, DISPATCHER_HOVERING_LIST, DISPATCHER_HOVERING_STYLE, Keyboard
+ PointerManager, print, Keyboard
*/
controllerDispatcherPlugins = {};
@@ -53,6 +53,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
this.blacklist = [];
this.pointerManager = new PointerManager();
this.grabSphereOverlays = [null, null];
+ this.targetIDs = {};
// a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are
// not set to false (not in use), a module cannot start. When a module is using a slot, that module's name
@@ -225,8 +226,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
if (tabletIndex !== -1 && closebyOverlays.indexOf(HMD.tabletID) === -1) {
nearbyOverlays.splice(tabletIndex, 1);
}
- if (miniTabletIndex !== -1
- && ((closebyOverlays.indexOf(HMD.miniTabletID) === -1) || h !== HMD.miniTabletHand)) {
+ if (miniTabletIndex !== -1 &&
+ ((closebyOverlays.indexOf(HMD.miniTabletID) === -1) || h !== HMD.miniTabletHand)) {
nearbyOverlays.splice(miniTabletIndex, 1);
}
}
@@ -336,6 +337,23 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
});
}
+ // also make sure we have the properties from the current module's target
+ for (var tIDRunningPluginName in _this.runningPluginNames) {
+ if (_this.runningPluginNames.hasOwnProperty(tIDRunningPluginName)) {
+ var targetIDs = _this.targetIDs[tIDRunningPluginName];
+ if (targetIDs) {
+ for (var k = 0; k < targetIDs.length; k++) {
+ var targetID = targetIDs[k];
+ if (!nearbyEntityPropertiesByID[targetID]) {
+ var targetProps = Entities.getEntityProperties(targetID, DISPATCHER_PROPERTIES);
+ targetProps.id = targetID;
+ nearbyEntityPropertiesByID[targetID] = targetProps;
+ }
+ }
+ }
+ }
+ }
+
// bundle up all the data about the current situation
var controllerData = {
triggerValues: [_this.leftTriggerValue, _this.rightTriggerValue],
@@ -402,10 +420,23 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
Script.beginProfileRange("dispatch.run." + runningPluginName);
}
var runningness = plugin.run(controllerData, deltaTime);
+
+ if (DEBUG) {
+ if (JSON.stringify(_this.targetIDs[runningPluginName]) != JSON.stringify(runningness.targets)) {
+ print("controllerDispatcher targetIDs[" + runningPluginName + "] = " +
+ JSON.stringify(runningness.targets));
+ }
+ }
+
+ _this.targetIDs[runningPluginName] = runningness.targets;
if (!runningness.active) {
// plugin is finished running, for now. remove it from the list
// of running plugins and mark its activity-slots as "not in use"
delete _this.runningPluginNames[runningPluginName];
+ delete _this.targetIDs[runningPluginName];
+ if (DEBUG) {
+ print("controllerDispatcher deleted targetIDs[" + runningPluginName + "]");
+ }
_this.markSlots(plugin, false);
_this.pointerManager.makePointerInvisible(plugin.parameters.handLaser);
if (DEBUG) {
@@ -527,8 +558,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
}
if (action === "tablet") {
- var tabletIDs = message.blacklist
- ? [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] : [];
+ var tabletIDs = message.blacklist ?
+ [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID] :
+ [];
if (message.hand === LEFT_HAND) {
_this.leftBlacklistTabletIDs = tabletIDs;
_this.setLeftBlacklist();
diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js
index b1c1bc7765..54b56ff271 100644
--- a/scripts/system/controllers/controllerModules/equipEntity.js
+++ b/scripts/system/controllers/controllerModules/equipEntity.js
@@ -7,10 +7,10 @@
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, Camera, print, getControllerJointIndex,
- enableDispatcherModule, disableDispatcherModule, entityIsFarGrabbedByOther, Messages, makeDispatcherModuleParameters,
+ enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters,
makeRunningValues, Settings, entityHasActions, Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic,
- entityIsCloneable, cloneEntity, DISPATCHER_PROPERTIES, Uuid, unhighlightTargetEntity, isInEditMode, getGrabbableData,
- entityIsEquippable
+ entityIsCloneable, cloneEntity, DISPATCHER_PROPERTIES, Uuid, isInEditMode, getGrabbableData,
+ entityIsEquippable, HMD
*/
Script.include("/~/system/libraries/Xform.js");
@@ -183,8 +183,9 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
var TRIGGER_OFF_VALUE = 0.1;
var TRIGGER_ON_VALUE = TRIGGER_OFF_VALUE + 0.05; // Squeezed just enough to activate search or near grab
var BUMPER_ON_VALUE = 0.5;
+ var ATTACHPOINT_MAX_DISTANCE = 3.0;
- var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}";
+ // var EMPTY_PARENT_ID = "{00000000-0000-0000-0000-000000000000}";
var UNEQUIP_KEY = "u";
@@ -200,7 +201,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
indicatorOffset: props.grab.equippableIndicatorOffset
};
} else {
- return null
+ return null;
}
}
@@ -231,6 +232,12 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
var jointName = (hand === RIGHT_HAND) ? "RightHand" : "LeftHand";
var joints = avatarSettingsData[hotspot.key];
if (joints) {
+ // make sure they are reasonable
+ if (joints[jointName] && joints[jointName][0] &&
+ Vec3.length(joints[jointName][0]) > ATTACHPOINT_MAX_DISTANCE) {
+ print("equipEntity -- Warning: rejecting settings attachPoint " + Vec3.length(joints[jointName][0]));
+ return undefined;
+ }
return joints[jointName];
}
}
@@ -456,6 +463,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
};
this.startEquipEntity = function (controllerData) {
+ var _this = this;
+
this.dropGestureReset();
this.clearEquipHaptics();
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
@@ -498,17 +507,23 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
if (entityIsCloneable(grabbedProperties)) {
var cloneID = this.cloneHotspot(grabbedProperties, controllerData);
this.targetEntityID = cloneID;
- Entities.editEntity(this.targetEntityID, reparentProps);
controllerData.nearbyEntityPropertiesByID[this.targetEntityID] = grabbedProperties;
isClone = true;
- } else if (!grabbedProperties.locked) {
- Entities.editEntity(this.targetEntityID, reparentProps);
- } else {
+ } else if (grabbedProperties.locked) {
this.grabbedHotspot = null;
this.targetEntityID = null;
return;
}
+
+ // HACK -- when
+ // https://highfidelity.fogbugz.com/f/cases/21767/entity-edits-shortly-after-an-add-often-fail
+ // is resolved, this can just be an editEntity rather than a setTimeout.
+ this.editDelayTimeout = Script.setTimeout(function () {
+ _this.editDelayTimeout = null;
+ Entities.editEntity(_this.targetEntityID, reparentProps);
+ }, 100);
+
// we don't want to send startEquip message until the trigger is released. otherwise,
// guns etc will fire right as they are equipped.
this.shouldSendStart = true;
@@ -519,7 +534,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
}));
- var _this = this;
var grabEquipCheck = function() {
var args = [_this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(_this.targetEntityID, "startEquip", args);
@@ -532,6 +546,12 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
};
this.endEquipEntity = function () {
+
+ if (this.editDelayTimeout) {
+ Script.clearTimeout(this.editDelayTimeout);
+ this.editDelayTimeout = null;
+ }
+
this.storeAttachPointInSettings();
Entities.editEntity(this.targetEntityID, {
parentID: Uuid.NULL,
@@ -595,7 +615,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
equipHotspotBuddy.update(deltaTime, timestamp, controllerData);
// if the potentialHotspot is cloneable, clone it and return it
- // if the potentialHotspot os not cloneable and locked return null
+ // if the potentialHotspot is not cloneable and locked return null
if (potentialEquipHotspot &&
(((this.triggerSmoothedSqueezed() || this.secondarySmoothedSqueezed()) && !this.waitForTriggerRelease) ||
this.messageGrabEntity)) {
@@ -603,7 +623,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
this.targetEntityID = this.grabbedHotspot.entityID;
this.startEquipEntity(controllerData);
this.equipedWithSecondary = this.secondarySmoothedSqueezed();
- return makeRunningValues(true, [potentialEquipHotspot.entityID], []);
+ return makeRunningValues(true, [this.targetEntityID], []);
} else {
return makeRunningValues(false, [], []);
}
diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js
index e059081741..38287e3af3 100644
--- a/scripts/system/marketplaces/marketplaces.js
+++ b/scripts/system/marketplaces/marketplaces.js
@@ -615,11 +615,10 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
openMarketplace(message.itemId, message.itemEdition);
break;
case 'passphrasePopup_cancelClicked':
- case 'needsLogIn_cancelClicked':
// Should/must NOT check for wallet setup.
openMarketplace();
break;
- case 'needsLogIn_loginClicked':
+ case 'marketplace_loginClicked':
openLoginWindow();
break;
case 'disableHmdPreview':
diff --git a/tools/jsdoc/README.md b/tools/jsdoc/README.md
index f9864a21e4..f3dda84291 100644
--- a/tools/jsdoc/README.md
+++ b/tools/jsdoc/README.md
@@ -15,6 +15,13 @@ To generate html documentation for the High Fidelity JavaScript API:
The out folder should contain index.html.
+If you get a "JavaScript heap out of memory" error when running the `jsdoc` command you need to increase the amount of memory
+available to it. For example, to increase the memory available to 2GB on Windows:
+* `where jsdoc` to find the `jsdoc.cmd` file.
+* Edit the `jsdoc.cmd` file to add `--max-old-space-size=2048` after the `node` and/or `node.exe` commands.
+
+Reference: https://medium.com/@vuongtran/how-to-solve-process-out-of-memory-in-node-js-5f0de8f8464c
+
To generate the grav automation files, run node gravPrep.js after you have made a JSdoc output folder.
This will create files that are needed for hifi-grav and hifi-grav-content repos
diff --git a/tools/jsdoc/plugins/hifi.js b/tools/jsdoc/plugins/hifi.js
index b2b91de1c8..5ec94b46aa 100644
--- a/tools/jsdoc/plugins/hifi.js
+++ b/tools/jsdoc/plugins/hifi.js
@@ -107,6 +107,9 @@ exports.handlers = {
if (e.doclet.hifiClientEntity) {
rows.push("Client Entity Scripts");
}
+ if (e.doclet.hifiAvatar) {
+ rows.push("Avatar Scripts");
+ }
if (e.doclet.hifiServerEntity) {
rows.push("Server Entity Scripts");
}
@@ -146,6 +149,13 @@ exports.defineTags = function (dictionary) {
}
});
+ // @hifi-avatar-script
+ dictionary.defineTag("hifi-avatar", {
+ onTagged: function (doclet, tag) {
+ doclet.hifiAvatar = true;
+ }
+ });
+
// @hifi-client-entity
dictionary.defineTag("hifi-client-entity", {
onTagged: function (doclet, tag) {
diff --git a/tools/noramlizeFrame.py b/tools/noramlizeFrame.py
deleted file mode 100644
index f1012f6428..0000000000
--- a/tools/noramlizeFrame.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import os
-import json
-import shutil
-import sys
-
-def scriptRelative(*paths):
- scriptdir = os.path.dirname(os.path.realpath(sys.argv[0]))
- result = os.path.join(scriptdir, *paths)
- result = os.path.realpath(result)
- result = os.path.normcase(result)
- return result
-
-
-
-class FrameProcessor:
- def __init__(self, filename):
- self.filename = filename
- dir, name = os.path.split(self.filename)
- self.dir = dir
- self.ktxDir = os.path.join(self.dir, 'ktx')
- os.makedirs(self.ktxDir, exist_ok=True)
- self.resDir = scriptRelative("../interface/resources")
-
- if (name.endswith(".json")):
- self.name = name[0:-5]
- else:
- self.name = name
- self.filename = self.filename + '.json'
-
- with open(self.filename, 'r') as f:
- self.json = json.load(f)
-
-
- def processKtx(self, texture):
- if texture is None: return
- if not 'ktxFile' in texture: return
- sourceKtx = texture['ktxFile']
- if sourceKtx.startswith(':'):
- sourceKtx = sourceKtx[1:]
- while sourceKtx.startswith('/'):
- sourceKtx = sourceKtx[1:]
- sourceKtx = os.path.join(self.resDir, sourceKtx)
- sourceKtxDir, sourceKtxName = os.path.split(sourceKtx)
- destKtx = os.path.join(self.ktxDir, sourceKtxName)
- if not os.path.isfile(destKtx):
- shutil.copy(sourceKtx, destKtx)
- newValue = 'ktx/' + sourceKtxName
- texture['ktxFile'] = newValue
-
-
- def process(self):
- for texture in self.json['textures']:
- self.processKtx(texture)
-
- with open(self.filename, 'w') as f:
- json.dump(self.json, f, indent=2)
-
-fp = FrameProcessor("D:/Frames/20190114_1629.json")
-fp.process()
-
-
-#C:\Users\bdavi\git\hifi\interface\resources\meshes
\ No newline at end of file
diff --git a/tools/normalizeFrame.py b/tools/normalizeFrame.py
index 36b2038d5c..892609bbf0 100644
--- a/tools/normalizeFrame.py
+++ b/tools/normalizeFrame.py
@@ -36,7 +36,10 @@ class FrameProcessor:
if not 'ktxFile' in texture: return
sourceKtx = texture['ktxFile']
if sourceKtx.startswith(':'):
- sourceKtx = os.path.join(self.resDir, sourceKtx[3:])
+ sourceKtx = sourceKtx[1:]
+ while sourceKtx.startswith('/'):
+ sourceKtx = sourceKtx[1:]
+ sourceKtx = os.path.join(self.resDir, sourceKtx)
sourceKtxDir, sourceKtxName = os.path.split(sourceKtx)
destKtx = os.path.join(self.ktxDir, sourceKtxName)
if not os.path.isfile(destKtx):
@@ -52,7 +55,7 @@ class FrameProcessor:
with open(self.filename, 'w') as f:
json.dump(self.json, f, indent=2)
-fp = FrameProcessor("D:/Frames/20190110_1635.json")
+fp = FrameProcessor("D:/Frames/20190112_1647.json")
fp.process()
diff --git a/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter/AvatarExporter.cs b/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter/AvatarExporter.cs
index 11d83a52e8..4e06772f4b 100644
--- a/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter/AvatarExporter.cs
+++ b/tools/unity-avatar-exporter/Assets/Editor/AvatarExporter/AvatarExporter.cs
@@ -17,7 +17,7 @@ using System.Text.RegularExpressions;
class AvatarExporter : MonoBehaviour {
// update version number for every PR that changes this file, also set updated version in README file
- static readonly string AVATAR_EXPORTER_VERSION = "0.3.7";
+ static readonly string AVATAR_EXPORTER_VERSION = "0.4.0";
static readonly float HIPS_GROUND_MIN_Y = 0.01f;
static readonly float HIPS_SPINE_CHEST_MIN_SEPARATION = 0.001f;
@@ -697,11 +697,10 @@ class AvatarExporter : MonoBehaviour {
if (materialDatas.Count > 0) {
string materialJson = "{ ";
foreach (var materialData in materialDatas) {
- // if this is the only material in the mapping and it is the default name No Name mapped to No Name,
+ // if this is the only material in the mapping and it is mapped to default material name No Name,
// then the avatar has no embedded materials and this material should be applied to all meshes
string materialName = materialData.Key;
- if (materialMappings.Count == 1 && materialName == DEFAULT_MATERIAL_NAME &&
- materialMappings[materialName] == DEFAULT_MATERIAL_NAME) {
+ if (materialMappings.Count == 1 && materialName == DEFAULT_MATERIAL_NAME) {
materialJson += "\"all\": ";
} else {
materialJson += "\"mat::" + materialName + "\": ";
@@ -1300,6 +1299,7 @@ class ExportProjectWindow : EditorWindow {
const float DEFAULT_AVATAR_HEIGHT = 1.755f;
const float MAXIMUM_RECOMMENDED_HEIGHT = DEFAULT_AVATAR_HEIGHT * 1.5f;
const float MINIMUM_RECOMMENDED_HEIGHT = DEFAULT_AVATAR_HEIGHT * 0.25f;
+ const float SLIDER_DIFFERENCE_REMOVE_TEXT = 0.01f;
readonly Color COLOR_YELLOW = Color.yellow; //new Color(0.9176f, 0.8274f, 0.0f);
readonly Color COLOR_BACKGROUND = new Color(0.5f, 0.5f, 0.5f);
@@ -1314,6 +1314,7 @@ class ExportProjectWindow : EditorWindow {
Vector2 warningScrollPosition = new Vector2(0, 0);
string scaleWarningText = "";
float sliderScale = 0.30103f;
+ float originalSliderScale;
public delegate void OnExportDelegate(string projectDirectory, string projectName, float scale);
OnExportDelegate onExportCallback;
@@ -1344,6 +1345,8 @@ class ExportProjectWindow : EditorWindow {
SetAvatarScale(newScale);
scaleWarningText = "Avatar's scale automatically adjusted to be within the recommended range.";
}
+
+ originalSliderScale = sliderScale;
}
void OnGUI() {
@@ -1460,10 +1463,9 @@ class ExportProjectWindow : EditorWindow {
Close();
}
- // when any value changes check for any errors and update scale warning if we are not exporting
+ // When a text field changes check for any errors if we didn't just check errors from clicking Export above
if (GUI.changed && !export) {
CheckForErrors(false);
- UpdateScaleWarning();
}
}
@@ -1521,13 +1523,14 @@ class ExportProjectWindow : EditorWindow {
}
void UpdateScaleWarning() {
- // called on any input changes
+ // called on any scale changes
float height = GetAvatarHeight();
if (height < MINIMUM_RECOMMENDED_HEIGHT) {
scaleWarningText = "The height of the avatar is below the recommended minimum.";
} else if (height > MAXIMUM_RECOMMENDED_HEIGHT) {
scaleWarningText = "The height of the avatar is above the recommended maximum.";
- } else {
+ } else if (Mathf.Abs(originalSliderScale - sliderScale) > SLIDER_DIFFERENCE_REMOVE_TEXT) {
+ // once moving slider beyond a small threshold, remove the automatically scaled text
scaleWarningText = "";
}
}
@@ -1555,6 +1558,8 @@ class ExportProjectWindow : EditorWindow {
// adjust slider scale value to match the new actual scale value
sliderScale = GetSliderScaleFromActualScale(actualScale);
+
+ UpdateScaleWarning();
}
float GetSliderScaleFromActualScale(float actualScale) {
diff --git a/tools/unity-avatar-exporter/Assets/README.txt b/tools/unity-avatar-exporter/Assets/README.txt
index 0b5cb49117..410314d8b4 100644
--- a/tools/unity-avatar-exporter/Assets/README.txt
+++ b/tools/unity-avatar-exporter/Assets/README.txt
@@ -1,6 +1,6 @@
High Fidelity, Inc.
Avatar Exporter
-Version 0.3.7
+Version 0.4.0
Note: It is recommended to use Unity versions between 2017.4.15f1 and 2018.2.12f1 for this Avatar Exporter.
diff --git a/tools/unity-avatar-exporter/avatarExporter.unitypackage b/tools/unity-avatar-exporter/avatarExporter.unitypackage
index d906cfc0a4..328972736b 100644
Binary files a/tools/unity-avatar-exporter/avatarExporter.unitypackage and b/tools/unity-avatar-exporter/avatarExporter.unitypackage differ