working on lookat (eye contact)

This commit is contained in:
Jeffrey Ventrella 2013-05-14 17:30:41 -07:00
parent 7117e4a76c
commit f53b49c496
7 changed files with 193 additions and 162 deletions

View file

@ -293,7 +293,9 @@ bool Avatar::getIsNearInteractingOther() {
void Avatar::simulate(float deltaTime) {
//figure out if the mouse cursor is over any body spheres...
checkForMouseRayTouching();
if (_isMine) {
checkForMouseRayTouching();
}
// update balls
if (_balls) { _balls->simulate(deltaTime); }
@ -519,6 +521,9 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
}
if (_interactingOther) {
_head.setLookatPosition( _interactingOther->getSpringyHeadPosition());
_avatarTouch.setYourBodyPosition(_interactingOther->_position);
_avatarTouch.setYourHandPosition(_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition);
_avatarTouch.setYourHandState (_interactingOther->_handState);
@ -592,115 +597,6 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
}
}
void Avatar::updateHead(float deltaTime) {
/*
// Decay head back to center if turned on
if (_isMine && _returnHeadToCenter) {
// Decay back toward center
_headPitch *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime);
_headYaw *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime);
_headRoll *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime);
}
// For invensense gyro, decay only slightly when roughly centered
if (_isMine) {
const float RETURN_RANGE = 15.0;
const float RETURN_STRENGTH = 2.0;
if (fabs(_headPitch) < RETURN_RANGE) { _headPitch *= (1.0f - RETURN_STRENGTH * deltaTime); }
if (fabs(_headYaw) < RETURN_RANGE) { _headYaw *= (1.0f - RETURN_STRENGTH * deltaTime); }
if (fabs(_headRoll) < RETURN_RANGE) { _headRoll *= (1.0f - RETURN_STRENGTH * deltaTime); }
}
if (_head.noise) {
// Move toward new target
_headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ;
_headYaw += (_head.yawTarget - _headYaw ) * 10 * deltaTime; // (1.f - DECAY*deltaTime);
_headRoll *= 1.f - (DECAY * deltaTime);
}
_head.leanForward *= (1.f - DECAY * 30 * deltaTime);
_head.leanSideways *= (1.f - DECAY * 30 * deltaTime);
// Update where the avatar's eyes are
//
// First, decide if we are making eye contact or not
if (randFloat() < 0.005) {
_head.eyeContact = !_head.eyeContact;
_head.eyeContact = 1;
if (!_head.eyeContact) {
// If we just stopped making eye contact,move the eyes markedly away
_head.eyeballPitch[0] = _head.eyeballPitch[1] = _head.eyeballPitch[0] + 5.0 + (randFloat() - 0.5) * 10;
_head.eyeballYaw [0] = _head.eyeballYaw [1] = _head.eyeballYaw [0] + 5.0 + (randFloat() - 0.5) * 5;
} else {
// If now making eye contact, turn head to look right at viewer
SetNewHeadTarget(0,0);
}
}
const float DEGREES_BETWEEN_VIEWER_EYES = 3;
const float DEGREES_TO_VIEWER_MOUTH = 7;
if (_head.eyeContact) {
// Should we pick a new eye contact target?
if (randFloat() < 0.01) {
// Choose where to look next
if (randFloat() < 0.1) {
_head.eyeContactTarget = MOUTH;
} else {
if (randFloat() < 0.5) _head.eyeContactTarget = LEFT_EYE; else _head.eyeContactTarget = RIGHT_EYE;
}
}
// Set eyeball pitch and yaw to make contact
float eye_target_yaw_adjust = 0;
float eye_target_pitch_adjust = 0;
if (_head.eyeContactTarget == LEFT_EYE) eye_target_yaw_adjust = DEGREES_BETWEEN_VIEWER_EYES;
if (_head.eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES;
if (_head.eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH;
_head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust;
_head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust;
}
if (_head.noise)
{
_headPitch += (randFloat() - 0.5) * 0.2 * _head.noiseEnvelope;
_headYaw += (randFloat() - 0.5) * 0.3 *_head.noiseEnvelope;
//PupilSize += (randFloat() - 0.5) * 0.001*NoiseEnvelope;
if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3];
if (!_head.eyeContact) {
if (randFloat() < 0.01) _head.eyeballPitch[0] = _head.eyeballPitch[1] = (randFloat() - 0.5) * 20;
if (randFloat() < 0.01) _head.eyeballYaw[0] = _head.eyeballYaw[1] = (randFloat()- 0.5) * 10;
}
if ((randFloat() < 0.005) && (fabs(_head.pitchTarget - _headPitch) < 1.0) && (fabs(_head.yawTarget - _headYaw) < 1.0)) {
SetNewHeadTarget((randFloat()-0.5) * 20.0, (randFloat()-0.5) * 45.0);
}
if (0) {
// Pick new target
_head.pitchTarget = (randFloat() - 0.5) * 45;
_head.yawTarget = (randFloat() - 0.5) * 22;
}
if (randFloat() < 0.01)
{
_head.eyebrowPitch[0] = _head.eyebrowPitch[1] = BrowPitchAngle[rand()%3];
_head.eyebrowRoll [0] = _head.eyebrowRoll[1] = BrowRollAngle[rand()%5];
_head.eyebrowRoll [1] *=-1;
}
}
// Update audio trailing average for rendering facial animations
const float AUDIO_AVERAGING_SECS = 0.05;
_head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness +
(deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness;
*/
}
float Avatar::getHeight() {
return _height;
}

View file

@ -195,9 +195,6 @@ private:
glm::vec3 _mouseRayDirection;
glm::vec3 _cameraPosition;
//AvatarJointID _jointTouched;
// private methods...
void initializeSkeleton();
void updateSkeleton();
@ -205,7 +202,6 @@ private:
void updateBodySprings( float deltaTime );
void calculateBoneLengths();
void readSensors();
void updateHead( float deltaTime );
void updateHandMovementAndTouching(float deltaTime);
void updateAvatarCollisions(float deltaTime);
void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime );

View file

@ -7,6 +7,7 @@
//
#include "Head.h"
#include "Util.h"
#include <vector>
#include <SharedUtil.h>
#include <lodepng.h>
@ -15,6 +16,8 @@ using namespace std;
const float HEAD_MOTION_DECAY = 0.1;
const bool TESTING_LOOKAT = false;
float _browColor [] = {210.0/255.0, 105.0/255.0, 30.0/255.0};
float _mouthColor[] = {1, 0, 0};
@ -49,6 +52,7 @@ void Head::initialize() {
audioLoudness = 0.0;
skinColor = glm::vec3(0.0f, 0.0f, 0.0f);
position = glm::vec3(0.0f, 0.0f, 0.0f);
lookatPosition = glm::vec3(0.0f, 0.0f, 0.0f);
yaw = 0.0f;
pitch = 0.0f;
roll = 0.0f;
@ -219,11 +223,21 @@ void Head::simulate(float deltaTime, bool isMine) {
const float AUDIO_AVERAGING_SECS = 0.05;
averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * averageLoudness +
(deltaTime / AUDIO_AVERAGING_SECS) * audioLoudness;
}
void Head::setLookatPosition(glm::vec3 l) {
lookatPosition = l;
}
void Head::render(bool lookingInMirror, float bodyYaw) {
//float a = angleBetween( &position, &position);
int side = 0;
glEnable(GL_DEPTH_TEST);
@ -236,11 +250,11 @@ void Head::render(bool lookingInMirror, float bodyYaw) {
glScalef(scale, scale, scale);
if (lookingInMirror) {
glRotatef(bodyYaw - yaw, 0, 1, 0);
glRotatef(bodyYaw - yaw, 0, 1, 0);
glRotatef(pitch, 1, 0, 0);
glRotatef(-roll, 0, 0, 1);
} else {
glRotatef(bodyYaw + yaw, 0, 1, 0);
glRotatef(bodyYaw + yaw, 0, 1, 0);
glRotatef(pitch, 1, 0, 0);
glRotatef(roll, 0, 0, 1);
}
@ -290,24 +304,37 @@ void Head::render(bool lookingInMirror, float bodyYaw) {
// Mouth
glPushMatrix();
glTranslatef(0,-0.35,0.75);
glColor3f(0,0,0);
glTranslatef(0,-0.35,0.75);
glColor3f(0,0,0);
glRotatef(mouthPitch, 1, 0, 0);
glRotatef(mouthYaw, 0, 0, 1);
glRotatef(mouthPitch, 1, 0, 0);
glRotatef(mouthYaw, 0, 0, 1);
if (averageLoudness > 1.f) {
glScalef(mouthWidth * (.7f + sqrt(averageLoudness) /60.f),
mouthHeight * (1.f + sqrt(averageLoudness) /30.f), 1);
} else {
glScalef(mouthWidth, mouthHeight, 1);
}
if (averageLoudness > 1.f) {
glScalef(mouthWidth * (.7f + sqrt(averageLoudness) /60.f),
mouthHeight * (1.f + sqrt(averageLoudness) /30.f), 1);
} else {
glScalef(mouthWidth, mouthHeight, 1);
}
glutSolidCube(0.5);
glutSolidCube(0.5);
glPopMatrix();
glTranslatef(0, 1.0, 0);
renderEyeBalls();
glPopMatrix();
if (TESTING_LOOKAT) {
//the irises are special - they have the ability to look at specific targets in the world (code still not finished yet)
renderIrises(bodyYaw + yaw);
}
}
void Head::renderEyeBalls() {
glTranslatef(0, 1.0, 0);
glTranslatef(-interPupilDistance/2.0,-0.68,0.7);
// Right Eye
@ -322,30 +349,33 @@ void Head::render(bool lookingInMirror, float bodyYaw) {
}
glPopMatrix();
// Right Pupil
if (sphere == NULL) {
sphere = gluNewQuadric();
gluQuadricTexture(sphere, GL_TRUE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gluQuadricOrientation(sphere, GLU_OUTSIDE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iris_texture_width, iris_texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &iris_texture[0]);
if (!TESTING_LOOKAT) {
// Right Pupil
if (sphere == NULL) {
sphere = gluNewQuadric();
gluQuadricTexture(sphere, GL_TRUE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gluQuadricOrientation(sphere, GLU_OUTSIDE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iris_texture_width, iris_texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &iris_texture[0]);
}
glPushMatrix();
{
glRotatef(eyeballPitch[1], 1, 0, 0);
glRotatef(eyeballYaw[1] + yaw + pupilConverge, 0, 1, 0);
glTranslatef(0,0,.35);
glRotatef(-75,1,0,0);
glScalef(1.0, 0.4, 1.0);
glEnable(GL_TEXTURE_2D);
gluSphere(sphere, pupilSize, 15, 15);
glDisable(GL_TEXTURE_2D);
}
glPopMatrix();
}
glPushMatrix();
{
glRotatef(eyeballPitch[1], 1, 0, 0);
glRotatef(eyeballYaw[1] + yaw + pupilConverge, 0, 1, 0);
glTranslatef(0,0,.35);
glRotatef(-75,1,0,0);
glScalef(1.0, 0.4, 1.0);
glEnable(GL_TEXTURE_2D);
gluSphere(sphere, pupilSize, 15, 15);
glDisable(GL_TEXTURE_2D);
}
glPopMatrix();
// Left Eye
glColor3fv(_eyeColor);
glTranslatef(interPupilDistance, 0, 0);
@ -357,21 +387,111 @@ void Head::render(bool lookingInMirror, float bodyYaw) {
glutSolidSphere(0.25, 30, 30);
}
glPopMatrix();
// Left Pupil
if (!TESTING_LOOKAT) {
// Left Pupil
glPushMatrix();
{
glRotatef(eyeballPitch[0], 1, 0, 0);
glRotatef(eyeballYaw[0] + yaw - pupilConverge, 0, 1, 0);
glTranslatef(0, 0, .35);
glRotatef(-75, 1, 0, 0);
glScalef(1.0, 0.4, 1.0);
glEnable(GL_TEXTURE_2D);
gluSphere(sphere, pupilSize, 15, 15);
glDisable(GL_TEXTURE_2D);
}
glPopMatrix();
}
}
//---------------------------------------------------------
// the code below is still in the prototyping stages....
//---------------------------------------------------------
void Head::renderIrises(float yaw) {
Orientation orientation;
orientation.setToPitchYawRoll( pitch, yaw, roll);
// Render lines originating from the eyes and converging on the lookatPosition
float rightShift = scale * 0.22f;
float upShift = scale * 0.38f;
float frontShift = scale * 0.9f;
glm::vec3 leftEyePosition = position + orientation.getRight() * rightShift
+ orientation.getUp () * upShift
+ orientation.getFront() * frontShift;
glm::vec3 rightEyePosition = position - orientation.getRight() * rightShift
+ orientation.getUp () * upShift
+ orientation.getFront() * frontShift;
debugRenderLookatVectors(leftEyePosition, rightEyePosition, lookatPosition);
glColor3fv(_eyeColor);
if (sphere == NULL) {
sphere = gluNewQuadric();
gluQuadricTexture(sphere, GL_TRUE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gluQuadricOrientation(sphere, GLU_OUTSIDE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iris_texture_width, iris_texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &iris_texture[0]);
}
//render left iris
glPushMatrix();
{
glRotatef(eyeballPitch[0], 1, 0, 0);
glRotatef(eyeballYaw[0] + yaw - pupilConverge, 0, 1, 0);
glTranslatef(0, 0, .35);
glRotatef(-75, 1, 0, 0);
glScalef(1.0, 0.4, 1.0);
glTranslatef(leftEyePosition.x, leftEyePosition.y, leftEyePosition.z);
glm::vec3 targetLookatAxis = glm::normalize(lookatPosition - leftEyePosition);
glEnable(GL_TEXTURE_2D);
gluSphere(sphere, pupilSize, 15, 15);
glDisable(GL_TEXTURE_2D);
glPushMatrix();
glm::vec3 pitchRotationAxis = glm::cross(targetLookatAxis, orientation.getRight());
glm::vec3 yawRotationAxis = glm::cross(targetLookatAxis, orientation.getUp());
glRotatef(90.0f, yawRotationAxis.x, yawRotationAxis.y, yawRotationAxis.z);
glRotatef(90.0f, pitchRotationAxis.x, pitchRotationAxis.y, pitchRotationAxis.z);
glEnable(GL_TEXTURE_2D);
gluSphere(sphere, 0.01, 15, 15);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
glPopMatrix();
//render right iris
glPushMatrix();
{
glTranslatef(rightEyePosition.x, rightEyePosition.y, rightEyePosition.z);
glm::vec3 targetLookatAxis = glm::normalize(lookatPosition - rightEyePosition);
glPushMatrix();
glm::vec3 pitchRotationAxis = glm::cross(targetLookatAxis, orientation.getRight());
glm::vec3 yawRotationAxis = glm::cross(targetLookatAxis, orientation.getUp());
glRotatef(90.0f, yawRotationAxis.x, yawRotationAxis.y, yawRotationAxis.z);
glRotatef(90.0f, pitchRotationAxis.x, pitchRotationAxis.y, pitchRotationAxis.z);
glEnable(GL_TEXTURE_2D);
gluSphere(sphere, 0.01, 15, 15);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
glPopMatrix();
}
void Head::debugRenderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
glColor3f(0.0f, 0.0f, 0.0f);
glLineWidth(3.0);
glBegin(GL_LINE_STRIP);
glVertex3f(leftEyePosition.x, leftEyePosition.y, leftEyePosition.z);
glVertex3f(lookatPosition.x, lookatPosition.y, lookatPosition.z);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(rightEyePosition.x, rightEyePosition.y, rightEyePosition.z);
glVertex3f(lookatPosition.x, lookatPosition.y, lookatPosition.z);
glEnd();
}

View file

@ -15,6 +15,7 @@
#include "world.h"
#include "InterfaceConfig.h"
#include "SerialInterface.h"
#include "Orientation.h"
enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH};
@ -30,6 +31,7 @@ public:
void render(bool lookingInMirror, float bodyYaw);
void setNewTarget(float, float);
void setSpringScale(float s) { returnSpringScale = s; }
void setLookatPosition(glm::vec3 lookatPosition);
// Do you want head to try to return to center (depends on interface detected)
void setReturnToCenter(bool r) { returnHeadToCenter = r; }
@ -43,6 +45,7 @@ public:
glm::vec3 skinColor;
glm::vec3 position;
glm::vec3 rotation;
glm::vec3 lookatPosition;
float yaw;
float pitch;
float roll;
@ -85,6 +88,12 @@ public:
// Strength of return springs
float returnSpringScale;
private:
void renderEyeBalls();
void renderIrises(float yaw);
void debugRenderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
};
#endif

View file

@ -1059,6 +1059,7 @@ void display(void)
myCamera.setTargetRotation(myAvatar.getBodyYaw() + myAvatar.getHeadYaw(), -myAvatar.getHeadPitch(), myAvatar.getHeadRoll());
} else if (myCamera.getMode() == CAMERA_MODE_MIRROR) {
myCamera.setTightness (100.0f);
myCamera.setTargetPosition(myAvatar.getSpringyHeadPosition());
myCamera.setTargetRotation(myAvatar.getBodyYaw() - 180.0f, 0.0f, 0.0f);
@ -1086,7 +1087,6 @@ void display(void)
glPopMatrix();
*/
// Note: whichCamera is used to pick between the normal camera myCamera for our
// main camera, vs, an alternate camera. The alternate camera we support right now
// is the viewFrustumOffsetCamera. But theoretically, we could use this same mechanism

View file

@ -25,6 +25,15 @@ void Orientation::setToIdentity() {
front = glm::vec3(IDENTITY_FRONT);
}
void Orientation::setToPitchYawRoll(float p, float y, float r) {
setToIdentity();
pitch(p);
yaw (y);
roll (r);
}
void Orientation::set(Orientation o) {
quat = o.quat;

View file

@ -22,6 +22,7 @@ public:
Orientation();
void set(Orientation);
void setToPitchYawRoll(float p, float y, float r);
void setToIdentity();
void pitch(float p);