mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 20:03:06 +02:00
Merge pull request #3488 from PhilipRosedale/master
Correct eye contact for Oculus users
This commit is contained in:
commit
7c738edbd8
8 changed files with 102 additions and 47 deletions
|
@ -1997,8 +1997,16 @@ void Application::updateMyAvatarLookAtPosition() {
|
||||||
glm::vec3 lookAtSpot;
|
glm::vec3 lookAtSpot;
|
||||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
// When I am in mirror mode, just look right at the camera (myself)
|
// When I am in mirror mode, just look right at the camera (myself)
|
||||||
lookAtSpot = _myCamera.getPosition();
|
if (!OculusManager::isConnected()) {
|
||||||
|
lookAtSpot = _myCamera.getPosition();
|
||||||
|
} else {
|
||||||
|
if (_myAvatar->isLookingAtLeftEye()) {
|
||||||
|
lookAtSpot = OculusManager::getLeftEyePosition();
|
||||||
|
} else {
|
||||||
|
lookAtSpot = OculusManager::getRightEyePosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().toStrongRef();
|
AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().toStrongRef();
|
||||||
if (lookingAt && _myAvatar != lookingAt.data()) {
|
if (lookingAt && _myAvatar != lookingAt.data()) {
|
||||||
|
@ -2006,7 +2014,7 @@ void Application::updateMyAvatarLookAtPosition() {
|
||||||
isLookingAtSomeone = true;
|
isLookingAtSomeone = true;
|
||||||
// If I am looking at someone else, look directly at one of their eyes
|
// If I am looking at someone else, look directly at one of their eyes
|
||||||
if (tracker) {
|
if (tracker) {
|
||||||
// If tracker active, look at the eye for the side my gaze is biased toward
|
// If a face tracker is active, look at the eye for the side my gaze is biased toward
|
||||||
if (tracker->getEstimatedEyeYaw() > _myAvatar->getHead()->getFinalYaw()) {
|
if (tracker->getEstimatedEyeYaw() > _myAvatar->getHead()->getFinalYaw()) {
|
||||||
// Look at their right eye
|
// Look at their right eye
|
||||||
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getRightEyePosition();
|
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getRightEyePosition();
|
||||||
|
@ -2016,7 +2024,11 @@ void Application::updateMyAvatarLookAtPosition() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Need to add randomly looking back and forth between left and right eye for case with no tracker
|
// Need to add randomly looking back and forth between left and right eye for case with no tracker
|
||||||
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getEyePosition();
|
if (_myAvatar->isLookingAtLeftEye()) {
|
||||||
|
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getLeftEyePosition();
|
||||||
|
} else {
|
||||||
|
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getRightEyePosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// I am not looking at anyone else, so just look forward
|
// I am not looking at anyone else, so just look forward
|
||||||
|
|
|
@ -110,7 +110,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||||
bool forceBlink = false;
|
bool forceBlink = false;
|
||||||
const float TALKING_LOUDNESS = 100.0f;
|
const float TALKING_LOUDNESS = 100.0f;
|
||||||
const float BLINK_AFTER_TALKING = 0.25f;
|
const float BLINK_AFTER_TALKING = 0.25f;
|
||||||
if (_averageLoudness > TALKING_LOUDNESS) {
|
if ((_averageLoudness - _longTermAverageLoudness) > TALKING_LOUDNESS) {
|
||||||
_timeWithoutTalking = 0.0f;
|
_timeWithoutTalking = 0.0f;
|
||||||
|
|
||||||
} else if (_timeWithoutTalking < BLINK_AFTER_TALKING && (_timeWithoutTalking += deltaTime) >= BLINK_AFTER_TALKING) {
|
} else if (_timeWithoutTalking < BLINK_AFTER_TALKING && (_timeWithoutTalking += deltaTime) >= BLINK_AFTER_TALKING) {
|
||||||
|
@ -118,7 +118,8 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update audio attack data for facial animation (eyebrows and mouth)
|
// Update audio attack data for facial animation (eyebrows and mouth)
|
||||||
_audioAttack = 0.9f * _audioAttack + 0.1f * fabs((_audioLoudness - _longTermAverageLoudness) - _lastLoudness);
|
const float AUDIO_ATTACK_AVERAGING_RATE = 0.9f;
|
||||||
|
_audioAttack = AUDIO_ATTACK_AVERAGING_RATE * _audioAttack + (1.0f - AUDIO_ATTACK_AVERAGING_RATE) * fabs((_audioLoudness - _longTermAverageLoudness) - _lastLoudness);
|
||||||
_lastLoudness = (_audioLoudness - _longTermAverageLoudness);
|
_lastLoudness = (_audioLoudness - _longTermAverageLoudness);
|
||||||
|
|
||||||
const float BROW_LIFT_THRESHOLD = 100.0f;
|
const float BROW_LIFT_THRESHOLD = 100.0f;
|
||||||
|
@ -128,16 +129,23 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||||
_browAudioLift = glm::clamp(_browAudioLift *= 0.7f, 0.0f, 1.0f);
|
_browAudioLift = glm::clamp(_browAudioLift *= 0.7f, 0.0f, 1.0f);
|
||||||
|
|
||||||
const float BLINK_SPEED = 10.0f;
|
const float BLINK_SPEED = 10.0f;
|
||||||
|
const float BLINK_SPEED_VARIABILITY = 1.0f;
|
||||||
|
const float BLINK_START_VARIABILITY = 0.25f;
|
||||||
const float FULLY_OPEN = 0.0f;
|
const float FULLY_OPEN = 0.0f;
|
||||||
const float FULLY_CLOSED = 1.0f;
|
const float FULLY_CLOSED = 1.0f;
|
||||||
if (_leftEyeBlinkVelocity == 0.0f && _rightEyeBlinkVelocity == 0.0f) {
|
if (_leftEyeBlinkVelocity == 0.0f && _rightEyeBlinkVelocity == 0.0f) {
|
||||||
// no blinking when brows are raised; blink less with increasing loudness
|
// no blinking when brows are raised; blink less with increasing loudness
|
||||||
const float BASE_BLINK_RATE = 15.0f / 60.0f;
|
const float BASE_BLINK_RATE = 15.0f / 60.0f;
|
||||||
const float ROOT_LOUDNESS_TO_BLINK_INTERVAL = 0.25f;
|
const float ROOT_LOUDNESS_TO_BLINK_INTERVAL = 0.25f;
|
||||||
if (forceBlink || (_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(_averageLoudness) *
|
if (forceBlink || (_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(fabs(_averageLoudness - _longTermAverageLoudness)) *
|
||||||
ROOT_LOUDNESS_TO_BLINK_INTERVAL) / BASE_BLINK_RATE, deltaTime))) {
|
ROOT_LOUDNESS_TO_BLINK_INTERVAL) / BASE_BLINK_RATE, deltaTime))) {
|
||||||
_leftEyeBlinkVelocity = BLINK_SPEED;
|
_leftEyeBlinkVelocity = BLINK_SPEED + randFloat() * BLINK_SPEED_VARIABILITY;
|
||||||
_rightEyeBlinkVelocity = BLINK_SPEED;
|
_rightEyeBlinkVelocity = BLINK_SPEED + randFloat() * BLINK_SPEED_VARIABILITY;
|
||||||
|
if (randFloat() < 0.5f) {
|
||||||
|
_leftEyeBlink = BLINK_START_VARIABILITY;
|
||||||
|
} else {
|
||||||
|
_rightEyeBlink = BLINK_START_VARIABILITY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
|
_leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
|
||||||
|
|
|
@ -86,7 +86,8 @@ MyAvatar::MyAvatar() :
|
||||||
_shouldRender(true),
|
_shouldRender(true),
|
||||||
_billboardValid(false),
|
_billboardValid(false),
|
||||||
_physicsSimulation(),
|
_physicsSimulation(),
|
||||||
_voxelShapeManager()
|
_voxelShapeManager(),
|
||||||
|
_isLookingAtLeftEye(true)
|
||||||
{
|
{
|
||||||
ShapeCollider::initDispatchTable();
|
ShapeCollider::initDispatchTable();
|
||||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||||
|
@ -978,7 +979,11 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
||||||
howManyLookingAtMe++;
|
howManyLookingAtMe++;
|
||||||
// Have that avatar look directly at my camera
|
// Have that avatar look directly at my camera
|
||||||
// Philip TODO: correct to look at left/right eye
|
// Philip TODO: correct to look at left/right eye
|
||||||
avatar->getHead()->setCorrectedLookAtPosition(Application::getInstance()->getViewFrustum()->getPosition());
|
if (OculusManager::isConnected()) {
|
||||||
|
avatar->getHead()->setCorrectedLookAtPosition(OculusManager::getLeftEyePosition());
|
||||||
|
} else {
|
||||||
|
avatar->getHead()->setCorrectedLookAtPosition(Application::getInstance()->getViewFrustum()->getPosition());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
avatar->getHead()->clearCorrectedLookAtPosition();
|
avatar->getHead()->clearCorrectedLookAtPosition();
|
||||||
}
|
}
|
||||||
|
@ -993,6 +998,14 @@ void MyAvatar::clearLookAtTargetAvatar() {
|
||||||
_lookAtTargetAvatar.clear();
|
_lookAtTargetAvatar.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MyAvatar::isLookingAtLeftEye() {
|
||||||
|
float const CHANCE_OF_CHANGING_EYE = 0.01f;
|
||||||
|
if (randFloat() < CHANCE_OF_CHANGING_EYE) {
|
||||||
|
_isLookingAtLeftEye = !_isLookingAtLeftEye;
|
||||||
|
}
|
||||||
|
return _isLookingAtLeftEye;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getUprightHeadPosition() const {
|
glm::vec3 MyAvatar::getUprightHeadPosition() const {
|
||||||
return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f);
|
return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,8 @@ public:
|
||||||
void jump() { _shouldJump = true; };
|
void jump() { _shouldJump = true; };
|
||||||
|
|
||||||
bool isMyAvatar() { return true; }
|
bool isMyAvatar() { return true; }
|
||||||
|
|
||||||
|
bool isLookingAtLeftEye();
|
||||||
|
|
||||||
virtual int parseDataAtOffset(const QByteArray& packet, int offset);
|
virtual int parseDataAtOffset(const QByteArray& packet, int offset);
|
||||||
|
|
||||||
|
@ -230,6 +232,8 @@ private:
|
||||||
QList<AnimationHandlePointer> _animationHandles;
|
QList<AnimationHandlePointer> _animationHandles;
|
||||||
PhysicsSimulation _physicsSimulation;
|
PhysicsSimulation _physicsSimulation;
|
||||||
VoxelShapeManager _voxelShapeManager;
|
VoxelShapeManager _voxelShapeManager;
|
||||||
|
|
||||||
|
bool _isLookingAtLeftEye;
|
||||||
|
|
||||||
RecorderPointer _recorder;
|
RecorderPointer _recorder;
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,9 @@ bool OculusManager::_programInitialized = false;
|
||||||
Camera* OculusManager::_camera = NULL;
|
Camera* OculusManager::_camera = NULL;
|
||||||
int OculusManager::_activeEyeIndex = -1;
|
int OculusManager::_activeEyeIndex = -1;
|
||||||
|
|
||||||
|
glm::vec3 OculusManager::_leftEyePosition;
|
||||||
|
glm::vec3 OculusManager::_rightEyePosition;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void OculusManager::connect() {
|
void OculusManager::connect() {
|
||||||
|
@ -348,6 +351,17 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
||||||
_camera->setTargetRotation(bodyOrientation * orientation);
|
_camera->setTargetRotation(bodyOrientation * orientation);
|
||||||
_camera->setTargetPosition(position + trackerPosition);
|
_camera->setTargetPosition(position + trackerPosition);
|
||||||
|
|
||||||
|
// Store the latest left and right eye render locations for things that need to know
|
||||||
|
glm::vec3 thisEyePosition = position + trackerPosition +
|
||||||
|
(bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) *
|
||||||
|
glm::vec3(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z));
|
||||||
|
|
||||||
|
if (eyeIndex == 0) {
|
||||||
|
_leftEyePosition = thisEyePosition;
|
||||||
|
} else {
|
||||||
|
_rightEyePosition = thisEyePosition;
|
||||||
|
}
|
||||||
|
|
||||||
_camera->update(1.0f / Application::getInstance()->getFps());
|
_camera->update(1.0f / Application::getInstance()->getFps());
|
||||||
|
|
||||||
Matrix4f proj = ovrMatrix4f_Projection(_eyeRenderDesc[eye].Fov, whichCamera.getNearClip(), whichCamera.getFarClip(), true);
|
Matrix4f proj = ovrMatrix4f_Projection(_eyeRenderDesc[eye].Fov, whichCamera.getNearClip(), whichCamera.getFarClip(), true);
|
||||||
|
@ -362,7 +376,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z);
|
glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z);
|
||||||
|
|
||||||
Application::getInstance()->displaySide(*_camera);
|
Application::getInstance()->displaySide(*_camera);
|
||||||
|
|
||||||
applicationOverlay.displayOverlayTextureOculus(*_camera);
|
applicationOverlay.displayOverlayTextureOculus(*_camera);
|
||||||
|
|
|
@ -45,7 +45,16 @@ public:
|
||||||
|
|
||||||
static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
||||||
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);
|
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBOVR
|
||||||
|
static glm::vec3 getLeftEyePosition() { return _leftEyePosition; }
|
||||||
|
static glm::vec3 getRightEyePosition() { return _rightEyePosition; }
|
||||||
|
#else
|
||||||
|
static glm::vec3 getLeftEyePosition() { return glm::vec3(); }
|
||||||
|
static glm::vec3 getRightEyePosition() { return glm::vec3(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef HAVE_LIBOVR
|
#ifdef HAVE_LIBOVR
|
||||||
static void generateDistortionMesh();
|
static void generateDistortionMesh();
|
||||||
|
@ -96,7 +105,12 @@ private:
|
||||||
static bool _programInitialized;
|
static bool _programInitialized;
|
||||||
static Camera* _camera;
|
static Camera* _camera;
|
||||||
static int _activeEyeIndex;
|
static int _activeEyeIndex;
|
||||||
|
static glm::vec3 _leftEyePosition;
|
||||||
|
static glm::vec3 _rightEyePosition;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_OculusManager_h
|
#endif // hifi_OculusManager_h
|
||||||
|
|
|
@ -13,50 +13,40 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "StdDev.h"
|
#include "StdDev.h"
|
||||||
|
|
||||||
const int MAX_STDEV_SAMPLES = 1000;
|
const int NUM_SAMPLES = 1000;
|
||||||
|
|
||||||
StDev::StDev() {
|
StDev::StDev() {
|
||||||
data = new float[MAX_STDEV_SAMPLES];
|
_data = new float[NUM_SAMPLES];
|
||||||
sampleCount = 0;
|
_sampleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StDev::reset() {
|
void StDev::reset() {
|
||||||
sampleCount = 0;
|
_sampleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StDev::addValue(float v) {
|
void StDev::addValue(float v) {
|
||||||
data[sampleCount++] = v;
|
_data[_sampleCount++] = v;
|
||||||
if (sampleCount == MAX_STDEV_SAMPLES) sampleCount = 0;
|
if (_sampleCount == NUM_SAMPLES) _sampleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float StDev::getAverage() const {
|
float StDev::getAverage() const {
|
||||||
float average = 0;
|
float average = 0;
|
||||||
for (int i = 0; i < sampleCount; i++) {
|
for (int i = 0; i < _sampleCount; i++) {
|
||||||
average += data[i];
|
average += _data[i];
|
||||||
}
|
}
|
||||||
if (sampleCount > 0)
|
if (_sampleCount > 0)
|
||||||
return average/(float)sampleCount;
|
return average / (float)_sampleCount;
|
||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
float StDev::getMax() {
|
|
||||||
float average = -FLT_MAX;
|
|
||||||
for (int i = 0; i < sampleCount; i++) {
|
|
||||||
average += data[i];
|
|
||||||
}
|
|
||||||
if (sampleCount > 0)
|
|
||||||
return average/(float)sampleCount;
|
|
||||||
else return 0;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
float StDev::getStDev() const {
|
float StDev::getStDev() const {
|
||||||
float average = getAverage();
|
float average = getAverage();
|
||||||
float stdev = 0;
|
float stdev = 0;
|
||||||
for (int i = 0; i < sampleCount; i++) {
|
for (int i = 0; i < _sampleCount; i++) {
|
||||||
stdev += powf(data[i] - average, 2);
|
stdev += powf(_data[i] - average, 2);
|
||||||
}
|
}
|
||||||
if (sampleCount > 1)
|
if (_sampleCount > 1)
|
||||||
return sqrt(stdev/(float)(sampleCount - 1.0));
|
return sqrt(stdev / (float)(_sampleCount - 1.0f));
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,16 +13,16 @@
|
||||||
#define hifi_StdDev_h
|
#define hifi_StdDev_h
|
||||||
|
|
||||||
class StDev {
|
class StDev {
|
||||||
public:
|
public:
|
||||||
StDev();
|
StDev();
|
||||||
void reset();
|
void reset();
|
||||||
void addValue(float v);
|
void addValue(float v);
|
||||||
float getAverage() const;
|
float getAverage() const;
|
||||||
float getStDev() const;
|
float getStDev() const;
|
||||||
int getSamples() const { return sampleCount; }
|
int getSamples() const { return _sampleCount; }
|
||||||
private:
|
private:
|
||||||
float * data;
|
float* _data;
|
||||||
int sampleCount;
|
int _sampleCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_StdDev_h
|
#endif // hifi_StdDev_h
|
||||||
|
|
Loading…
Reference in a new issue