Merge pull request #16245 from luiscuenca/implementPointAt

DEV-442: Implement directional blending node for point reaction
This commit is contained in:
Shannon Romano 2019-10-01 11:46:30 -07:00 committed by GitHub
commit 38574cd66b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 660 additions and 210 deletions

View file

@ -1544,103 +1544,292 @@
"type": "randomSwitchStateMachine"
},
{
"children": [
"children": [
{
"children": [
"children": [
{
"children": [
{
"children": [
],
"data": {
"endFrame": 21,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_all.fbx"
},
"id": "seatedReactionPointIntro",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 100,
"loopFlag": true,
"startFrame": 21,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_all.fbx"
},
"id": "seatedReactionPointLoop",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 134,
"loopFlag": false,
"mirrorFlag": false,
"startFrame": 100,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_all.fbx"
},
"id": "seatedReactionPointOutro",
"type": "clip"
}
],
"data": {
"currentState": "seatedReactionPointIntro",
"randomSwitchTimeMax": 10,
"randomSwitchTimeMin": 1,
"states": [
{
"easingType": "easeInOutQuad",
"id": "seatedReactionPointIntro",
"interpDuration": 18,
"interpTarget": 18,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
{
"randomSwitchState": "seatedReactionPointLoop",
"var": "seatedReactionPointIntroOnDone"
}
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedReactionPointLoop",
"interpDuration": 18,
"interpTarget": 18,
"interpType": "evaluateBoth",
"priority": 0,
"resume": false,
"transitions": [
{
"randomSwitchState": "seatedReactionPointOutro",
"var": "reactionPointDisabled"
}
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedReactionPointOutro",
"interpDuration": 18,
"interpTarget": 18,
"interpType": "evaluateBoth",
"priority": 0,
"resume": false,
"transitions": [
{
"randomSwitchState": "seatedReactionPointLoop",
"var": "reactionPointEnabled"
}
]
}
],
"triggerRandomSwitch": ""
},
"id": "seatedReactionPoint",
"type": "randomSwitchStateMachine"
}
],
"data": {
"endFrame": 21,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_all.fbx"
"alpha": 0,
"alphaVar": "seatedPointBlendAlpha",
"blendType": "addAbsolute"
},
"id": "seatedReactionPointIntro",
"type": "clip"
"id": "seatedReactionPointBase",
"type": "blendLinear"
},
{
"children": [
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 11,
"loopFlag": true,
"startFrame": 11,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointLeft",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 30,
"loopFlag": true,
"startFrame": 30,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointRight",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 50,
"loopFlag": true,
"startFrame": 50,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointUp",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 70,
"loopFlag": true,
"startFrame": 70,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointDown",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 90,
"loopFlag": true,
"startFrame": 90,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointUpLeft",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 110,
"loopFlag": true,
"startFrame": 110,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointUpRight",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 130,
"loopFlag": true,
"startFrame": 130,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointDownLeft",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 150,
"loopFlag": true,
"startFrame": 150,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointDownRight",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 3,
"loopFlag": true,
"startFrame": 3,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_aimoffsets.fbx"
},
"id": "seatedPointCenter",
"type": "clip"
}
],
"data": {
"endFrame": 100,
"loopFlag": true,
"startFrame": 21,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_all.fbx"
"alpha": [
0,
0,
0
],
"alphaVar": "pointAroundAlpha",
"centerId": "seatedPointCenter",
"downId": "seatedPointDown",
"downLeftId": "seatedPointDownLeft",
"downRightId": "seatedPointDownRight",
"leftId": "seatedPointLeft",
"rightId": "seatedPointRight",
"upId": "seatedPointUp",
"upLeftId": "seatedPointUpLeft",
"upRightId": "seatedPointUpRight"
},
"id": "seatedReactionPointLoop",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 134,
"loopFlag": false,
"mirrorFlag": false,
"startFrame": 100,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_emote_point_all.fbx"
},
"id": "seatedReactionPointOutro",
"type": "clip"
"id": "seatedPointAround",
"type": "blendDirectional"
}
],
"data": {
"currentState": "seatedReactionPointIntro",
"randomSwitchTimeMax": 10,
"randomSwitchTimeMin": 1,
"states": [
{
"easingType": "easeInOutQuad",
"id": "seatedReactionPointIntro",
"interpDuration": 18,
"interpTarget": 18,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
{
"randomSwitchState": "seatedReactionPointLoop",
"var": "seatedReactionPointIntroOnDone"
}
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedReactionPointLoop",
"interpDuration": 18,
"interpTarget": 18,
"interpType": "evaluateBoth",
"priority": 0,
"resume": false,
"transitions": [
{
"randomSwitchState": "seatedReactionPointOutro",
"var": "reactionPointDisabled"
}
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedReactionPointOutro",
"interpDuration": 18,
"interpTarget": 18,
"interpType": "evaluateBoth",
"priority": 0,
"resume": false,
"transitions": [
{
"randomSwitchState": "seatedReactionPointLoop",
"var": "reactionPointEnabled"
}
]
}
],
"triggerRandomSwitch": ""
"alpha": 0,
"alphaVar": "pointBlendAlpha",
"blendType": "addAbsolute"
},
"id": "seatedReactionPoint",
"type": "randomSwitchStateMachine"
"type": "blendLinear"
}
],
"data": {
@ -3531,97 +3720,275 @@
"children": [
{
"children": [
{
"children": [
],
"data": {
"endFrame": 21,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_all.fbx"
},
"id": "reactionPointIntro",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 100,
"loopFlag": true,
"startFrame": 21,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_all.fbx"
},
"id": "reactionPointLoop",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 134,
"loopFlag": false,
"startFrame": 100,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_all.fbx"
},
"id": "reactionPointOutro",
"type": "clip"
}
],
"data": {
"endFrame": 21,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_all.fbx"
"currentState": "reactionPointIntro",
"randomSwitchTimeMax": 10,
"randomSwitchTimeMin": 1,
"states": [
{
"easingType": "easeInOutQuad",
"id": "reactionPointIntro",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
{
"randomSwitchState": "reactionPointLoop",
"var": "reactionPointIntroOnDone"
}
]
},
{
"id": "reactionPointLoop",
"interpDuration": 1,
"interpTarget": 1,
"priority": 0,
"resume": false,
"transitions": [
{
"randomSwitchState": "reactionPointOutro",
"var": "reactionPointDisabled"
}
]
},
{
"easingType": "easeInOutQuad",
"id": "reactionPointOutro",
"interpDuration": 6,
"interpTarget": 6,
"interpType": "evaluateBoth",
"priority": 0,
"resume": false,
"transitions": [
{
"randomSwitchState": "reactionPointLoop",
"var": "reactionPointEnabled"
}
]
}
],
"triggerRandomSwitch": ""
},
"id": "reactionPointIntro",
"type": "clip"
"id": "reactionPoint",
"type": "randomSwitchStateMachine"
},
{
"children": [
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 11,
"loopFlag": true,
"startFrame": 11,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointLeft",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 30,
"loopFlag": true,
"startFrame": 30,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointRight",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 50,
"loopFlag": true,
"startFrame": 50,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointUp",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 70,
"loopFlag": true,
"startFrame": 70,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointDown",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 90,
"loopFlag": true,
"startFrame": 90,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointUpLeft",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 110,
"loopFlag": true,
"startFrame": 110,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointUpRight",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 130,
"loopFlag": true,
"startFrame": 130,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointDownLeft",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 150,
"loopFlag": true,
"startFrame": 150,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointDownRight",
"type": "clip"
},
{
"children": [
],
"data": {
"baseFrame": 1,
"baseURL": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx",
"blendType": "addAbsolute",
"endFrame": 3,
"loopFlag": true,
"startFrame": 3,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_aimoffsets.fbx"
},
"id": "idlePointCenter",
"type": "clip"
}
],
"data": {
"endFrame": 100,
"loopFlag": true,
"startFrame": 21,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_all.fbx"
"alpha": [
0,
0,
0
],
"alphaVar": "pointAroundAlpha",
"centerId": "idlePointCenter",
"downId": "idlePointDown",
"downLeftId": "idlePointDownLeft",
"downRightId": "idlePointDownRight",
"leftId": "idlePointLeft",
"rightId": "idlePointRight",
"upId": "idlePointUp",
"upLeftId": "idlePointUpLeft",
"upRightId": "idlePointUpRight"
},
"id": "reactionPointLoop",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 134,
"loopFlag": false,
"startFrame": 100,
"timeScale": 1,
"url": "qrc:///avatar/animations/emote_point01_all.fbx"
},
"id": "reactionPointOutro",
"type": "clip"
"id": "idlePointAround",
"type": "blendDirectional"
}
],
"data": {
"currentState": "reactionPointIntro",
"randomSwitchTimeMax": 10,
"randomSwitchTimeMin": 1,
"states": [
{
"easingType": "easeInOutQuad",
"id": "reactionPointIntro",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
{
"randomSwitchState": "reactionPointLoop",
"var": "reactionPointIntroOnDone"
}
]
},
{
"id": "reactionPointLoop",
"interpDuration": 1,
"interpTarget": 1,
"priority": 0,
"resume": false,
"transitions": [
{
"randomSwitchState": "reactionPointOutro",
"var": "reactionPointDisabled"
}
]
},
{
"easingType": "easeInOutQuad",
"id": "reactionPointOutro",
"interpDuration": 6,
"interpTarget": 6,
"interpType": "evaluateBoth",
"priority": 0,
"resume": false,
"transitions": [
{
"randomSwitchState": "reactionPointLoop",
"var": "reactionPointEnabled"
}
]
}
],
"triggerRandomSwitch": ""
"alpha": 0,
"alphaVar": "pointBlendAlpha",
"blendType": "addAbsolute"
},
"id": "reactionPoint",
"type": "randomSwitchStateMachine"
"type": "blendLinear"
}
],
"data": {
@ -5683,16 +6050,16 @@
"upLeftId": "lookUpLeft",
"upRightId": "lookUpRight"
},
"id": "lookAround",
"id": "lookAroundBlend",
"type": "blendDirectional"
}
],
"data": {
"alpha": 0,
"alphaVar": "additiveBlendAlpha",
"alphaVar": "lookBlendAlpha",
"blendType": "addAbsolute"
},
"id": "additiveBlend",
"id": "lookAround",
"type": "blendLinear"
}
],

View file

@ -99,10 +99,16 @@ static const QString USER_RECENTER_MODEL_FORCE_STAND = QStringLiteral("ForceStan
static const QString USER_RECENTER_MODEL_AUTO = QStringLiteral("Auto");
static const QString USER_RECENTER_MODEL_DISABLE_HMD_LEAN = QStringLiteral("DisableHMDLean");
const QString HEAD_BLENDING_NAME = "lookAroundAlpha";
const QString HEAD_ALPHA_NAME = "additiveBlendAlpha";
const QString HEAD_BLEND_DIRECTIONAL_ALPHA_NAME = "lookAroundAlpha";
const QString HEAD_BLEND_LINEAR_ALPHA_NAME = "lookBlendAlpha";
const float HEAD_ALPHA_BLENDING = 1.0f;
const QString POINT_REACTION_NAME = "point";
const QString POINT_BLEND_DIRECTIONAL_ALPHA_NAME = "pointAroundAlpha";
const QString POINT_BLEND_LINEAR_ALPHA_NAME = "pointBlendAlpha";
const QString POINT_REF_JOINT_NAME = "RightShoulder";
const float POINT_ALPHA_BLENDING = 1.0f;
MyAvatar::SitStandModelType stringToUserRecenterModel(const QString& str) {
if (str == USER_RECENTER_MODEL_FORCE_SIT) {
return MyAvatar::ForceSit;
@ -948,13 +954,16 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
qCDebug(interfaceapp) << "MyAvatar::simulate headPosition is NaN";
headPosition = glm::vec3(0.0f);
}
head->setPosition(headPosition);
head->setScale(getModelScale());
head->simulate(deltaTime);
CameraMode mode = qApp->getCamera().getMode();
if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
updateHeadLookAt(deltaTime);
if (!_pointAtActive || !_isPointTargetValid) {
updateHeadLookAt(deltaTime);
} else {
resetHeadLookAt();
}
} else if (_headLookAtActive){
resetHeadLookAt();
_headLookAtActive = false;
@ -6113,6 +6122,10 @@ bool MyAvatar::beginReaction(QString reactionName) {
if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_BEGIN_END_REACTIONS) {
std::lock_guard<std::mutex> guard(_reactionLock);
_reactionEnabledRefCounts[reactionIndex]++;
if (reactionName == POINT_REACTION_NAME) {
_pointAtActive = true;
_isPointTargetValid = true;
}
return true;
}
return false;
@ -6122,13 +6135,18 @@ bool MyAvatar::endReaction(QString reactionName) {
int reactionIndex = beginEndReactionNameToIndex(reactionName);
if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_BEGIN_END_REACTIONS) {
std::lock_guard<std::mutex> guard(_reactionLock);
bool wasReactionActive = true;
if (_reactionEnabledRefCounts[reactionIndex] > 0) {
_reactionEnabledRefCounts[reactionIndex]--;
return true;
wasReactionActive = true;
} else {
_reactionEnabledRefCounts[reactionIndex] = 0;
return false;
wasReactionActive = false;
}
if (reactionName == POINT_REACTION_NAME) {
_pointAtActive = _reactionEnabledRefCounts[reactionIndex] > 0;
}
return wasReactionActive;
}
return false;
}
@ -6139,10 +6157,13 @@ void MyAvatar::updateRigControllerParameters(Rig::ControllerParameters& params)
for (int i = 0; i < TRIGGER_REACTION_NAMES.size(); i++) {
params.reactionTriggers[i] = _reactionTriggers[i];
}
int pointReactionIndex = beginEndReactionNameToIndex("point");
for (int i = 0; i < BEGIN_END_REACTION_NAMES.size(); i++) {
// copy current state into params.
params.reactionEnabledFlags[i] = _reactionEnabledRefCounts[i] > 0;
if (params.reactionEnabledFlags[i] && i == pointReactionIndex) {
params.reactionEnabledFlags[i] = _isPointTargetValid;
}
}
for (int i = 0; i < TRIGGER_REACTION_NAMES.size(); i++) {
@ -6668,10 +6689,42 @@ void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera)
getHead()->setLookAtPosition(lookAtSpot);
}
glm::vec3 MyAvatar::aimToBlendValues(const glm::vec3& aimVector, const glm::quat& frameOrientation) {
// This method computes the values for the directional blending animation node
glm::vec3 uVector = glm::normalize(frameOrientation * Vectors::UNIT_X);
glm::vec3 vVector = glm::normalize(frameOrientation * Vectors::UNIT_Y);
glm::vec3 aimDirection;
if (glm::length(aimVector) > EPSILON) {
aimDirection = glm::normalize(aimVector);
} else {
// aim vector is zero
return glm::vec3();
}
float xDot = glm::dot(uVector, aimDirection);
float yDot = glm::dot(vVector, aimDirection);
// Make sure dot products are in range to avoid acosf returning NaN
xDot = glm::min(glm::max(xDot, -1.0f), 1.0f);
yDot = glm::min(glm::max(yDot, -1.0f), 1.0f);
float xAngle = acosf(xDot);
float yAngle = acosf(yDot);
// xBlend and yBlend are the values from -1.0 to 1.0 that set the directional blending.
// We compute them using the angles (0 to PI/2) => (1.0 to 0.0) and (PI/2 to PI) => (0.0 to -1.0)
float xBlend = -(xAngle - 0.5f * PI) / (0.5f * PI);
float yBlend = -(yAngle - 0.5f * PI) / (0.5f * PI);
glm::vec3 blendValues = glm::vec3(xBlend, yBlend, 0.0f);
return blendValues;
}
void MyAvatar::resetHeadLookAt() {
if (_skeletonModelLoaded) {
_skeletonModel->getRig().setDirectionalBlending(HEAD_BLENDING_NAME, glm::vec3(),
HEAD_ALPHA_NAME, HEAD_ALPHA_BLENDING);
_skeletonModel->getRig().setDirectionalBlending(HEAD_BLEND_DIRECTIONAL_ALPHA_NAME, glm::vec3(),
HEAD_BLEND_LINEAR_ALPHA_NAME, HEAD_ALPHA_BLENDING);
}
}
@ -6687,39 +6740,10 @@ void MyAvatar::resetLookAtRotation(const glm::vec3& avatarPosition, const glm::q
void MyAvatar::updateHeadLookAt(float deltaTime) {
if (_skeletonModelLoaded) {
glm::vec3 lookAtTarget = _scriptControlsHeadLookAt ? _lookAtScriptTarget : _lookAtCameraTarget;
glm::vec3 avatarXVector = glm::normalize(getWorldOrientation() * Vectors::UNIT_X);
glm::vec3 avatarYVector = glm::normalize(getWorldOrientation() * Vectors::UNIT_Y);
glm::vec3 avatarZVector = glm::normalize(getWorldOrientation() * Vectors::UNIT_Z);
glm::vec3 headToTargetVector = lookAtTarget - getDefaultEyePosition();
if (glm::length(headToTargetVector) > EPSILON) {
headToTargetVector = glm::normalize(headToTargetVector);
} else {
// The target point is the avatar head
return;
}
float xDot = glm::dot(avatarXVector, headToTargetVector);
float yDot = glm::dot(avatarYVector, headToTargetVector);
float zDot = glm::dot(avatarZVector, headToTargetVector);
// Force the head to look at one of the sides when the look at point is behind the avatar
if (zDot > 0.0f && xDot != 0.0f) {
//xDot /= fabsf(xDot);
}
// Make sure dot products are in range to avoid acosf returning NaN
xDot = glm::min(glm::max(xDot, -1.0f), 1.0f);
yDot = glm::min(glm::max(yDot, -1.0f), 1.0f);
float xAngle = acosf(xDot);
float yAngle = acosf(yDot);
// xBlend and yBlend are the values from -1.0 to 1.0 that set the directional blending.
// We compute them using the angles (0 to PI/2) => (1.0 to 0.0) and (PI/2 to PI) => (0.0 to -1.0)
float xBlend = -(xAngle - 0.5f * PI) / (0.5f * PI);
float yBlend = -(yAngle - 0.5f * PI) / (0.5f * PI);
glm::vec3 lookAtBlend = glm::vec3(xBlend, yBlend, 0.0f);
_skeletonModel->getRig().setDirectionalBlending(HEAD_BLENDING_NAME, lookAtBlend,
HEAD_ALPHA_NAME, HEAD_ALPHA_BLENDING);
glm::vec3 aimVector = lookAtTarget - getDefaultEyePosition();
glm::vec3 lookAtBlend = MyAvatar::aimToBlendValues(aimVector, getWorldOrientation());
_skeletonModel->getRig().setDirectionalBlending(HEAD_BLEND_DIRECTIONAL_ALPHA_NAME, lookAtBlend,
HEAD_BLEND_LINEAR_ALPHA_NAME, HEAD_ALPHA_BLENDING);
if (_scriptControlsHeadLookAt) {
_scriptHeadControlTimer += deltaTime;
@ -6743,3 +6767,30 @@ void MyAvatar::setHeadLookAt(const glm::vec3& lookAtTarget) {
_scriptHeadControlTimer = 0.0f;
_lookAtScriptTarget = lookAtTarget;
}
bool MyAvatar::setPointAt(const glm::vec3& pointAtTarget) {
if (QThread::currentThread() != thread()) {
bool result = false;
BLOCKING_INVOKE_METHOD(this, "setPointAt", Q_RETURN_ARG(bool, result),
Q_ARG(const glm::vec3&, pointAtTarget));
return result;
}
if (_skeletonModelLoaded && _pointAtActive) {
glm::vec3 aimVector = pointAtTarget - getJointPosition(POINT_REF_JOINT_NAME);
_isPointTargetValid = glm::dot(aimVector, getWorldOrientation() * Vectors::FRONT) > 0.0f;
if (_isPointTargetValid) {
glm::vec3 pointAtBlend = MyAvatar::aimToBlendValues(aimVector, getWorldOrientation());
_skeletonModel->getRig().setDirectionalBlending(POINT_BLEND_DIRECTIONAL_ALPHA_NAME, pointAtBlend,
POINT_BLEND_LINEAR_ALPHA_NAME, POINT_ALPHA_BLENDING);
}
return _isPointTargetValid;
}
return false;
}
void MyAvatar::resetPointAt() {
if (_skeletonModelLoaded) {
_skeletonModel->getRig().setDirectionalBlending(POINT_BLEND_DIRECTIONAL_ALPHA_NAME, glm::vec3(),
POINT_BLEND_LINEAR_ALPHA_NAME, POINT_ALPHA_BLENDING);
}
}

View file

@ -1765,6 +1765,16 @@ public:
*/
Q_INVOKABLE glm::vec3 getHeadLookAt() { return _lookAtCameraTarget; }
/**jsdoc
* Aims the pointing directional blending towards the provided target point.
* The "point" reaction should be triggered before using this method.
* <code>MyAvatar.beginReaction("point")</code>
* Returns <code>true</code> if the target point lays in front of the avatar.
* @function MyAvatar.setPointAt
* @param {Vec3} pointAtTarget - The target point in world coordinates.
*/
Q_INVOKABLE bool setPointAt(const glm::vec3& pointAtTarget);
glm::quat getLookAtRotation() { return _lookAtYaw * _lookAtPitch; }
/**jsdoc
@ -2653,6 +2663,8 @@ private:
bool _shouldTurnToFaceCamera { false };
bool _scriptControlsHeadLookAt { false };
float _scriptHeadControlTimer { 0.0f };
bool _pointAtActive { false };
bool _isPointTargetValid { true };
Setting::Handle<float> _realWorldFieldOfView;
Setting::Handle<bool> _useAdvancedMovementControls;
@ -2681,6 +2693,8 @@ private:
void updateHeadLookAt(float deltaTime);
void resetHeadLookAt();
void resetLookAtRotation(const glm::vec3& avatarPosition, const glm::quat& avatarOrientation);
void resetPointAt();
static glm::vec3 aimToBlendValues(const glm::vec3& aimVector, const glm::quat& frameOrientation);
// Avatar Preferences
QUrl _fullAvatarURLFromPreferences;

View file

@ -203,10 +203,20 @@ function maybeDeleteRemoteIndicatorTimeout() {
}
}
var reactionsBegun = [];
var pointReticle = null;
var mouseMoveEventsConnected = false;
var targetPointInterpolateConnected = false;
var pointAtTarget = Vec3.ZERO;
var isReticleVisible = true;
function targetPointInterpolate() {
if (reticlePosition) {
pointAtTarget = Vec3.mix(pointAtTarget, reticlePosition, POINT_AT_MIX_ALPHA);
isReticleVisible = MyAvatar.setPointAt(pointAtTarget);
}
}
function beginReactionWrapper(reaction) {
maybeDeleteRemoteIndicatorTimeout();
@ -227,14 +237,18 @@ function beginReactionWrapper(reaction) {
break;
case ("point"):
deleteOldReticles();
pointAtTarget = MyAvatar.getHeadLookAt();
if (!mouseMoveEventsConnected) {
Controller.mouseMoveEvent.connect(mouseMoveEvent);
mouseMoveEventsConnected = true;
}
if (!targetPointInterpolateConnected) {
Script.update.connect(targetPointInterpolate);
targetPointInterpolateConnected = true;
}
}
}
// Checks to see if there are any reticle entities already to delete
function deleteOldReticles() {
MyAvatar.getAvatarEntitiesVariant()
@ -250,6 +264,8 @@ function deleteOldReticles() {
var MAX_INTERSECTION_DISTANCE_M = 50;
var reticleUpdateRateLimiterTimer = false;
var RETICLE_UPDATE_RATE_LIMITER_TIMER_MS = 75;
var POINT_AT_MIX_ALPHA = 0.15;
var reticlePosition = Vec3.ZERO;
function mouseMoveEvent(event) {
if (!reticleUpdateRateLimiterTimer) {
reticleUpdateRateLimiterTimer = Script.setTimeout(function() {
@ -261,11 +277,10 @@ function mouseMoveEvent(event) {
var pickRay = Camera.computePickRay(event.x, event.y);
var avatarIntersectionData = AvatarManager.findRayIntersection(pickRay);
var avatarIntersectionData = AvatarManager.findRayIntersection(pickRay, [], [MyAvatar.sessionUUID], false);
var entityIntersectionData = Entities.findRayIntersection(pickRay, true);
var avatarIntersectionDistanceM = avatarIntersectionData.intersects && avatarIntersectionData.distance < MAX_INTERSECTION_DISTANCE_M ? avatarIntersectionData.distance : null;
var entityIntersectionDistanceM = entityIntersectionData.intersects && entityIntersectionData.distance < MAX_INTERSECTION_DISTANCE_M ? entityIntersectionData.distance : null;
var reticlePosition;
if (avatarIntersectionDistanceM && entityIntersectionDistanceM) {
if (avatarIntersectionDistanceM < entityIntersectionDistanceM) {
@ -283,7 +298,7 @@ function mouseMoveEvent(event) {
}
if (pointReticle && reticlePosition) {
Entities.editEntity(pointReticle, { position: reticlePosition });
Entities.editEntity(pointReticle, { position: reticlePosition, visible: isReticleVisible });
} else if (reticlePosition) {
pointReticle = Entities.addEntity({
type: "Box",
@ -349,6 +364,10 @@ function endReactionWrapper(reaction) {
Controller.mouseMoveEvent.disconnect(mouseMoveEvent);
mouseMoveEventsConnected = false;
}
if (targetPointInterpolateConnected) {
Script.update.disconnect(targetPointInterpolate);
targetPointInterpolateConnected = false;
}
maybeClearReticleUpdateLimiterTimeout();
deleteOldReticles();
break;
@ -757,7 +776,6 @@ function toggleEmojiApp() {
emojiAPI.registerAvimojiQMLWindow(emojiAppWindow);
}
// #endregion
// *************************************
// END EMOJI_MAIN