Basic blinking.

This commit is contained in:
Andrzej Kapolka 2013-06-21 18:11:31 -07:00
parent 81d0373bdc
commit ef7c6ebdc6
5 changed files with 203 additions and 2 deletions

View file

@ -33,6 +33,7 @@
#include "ViewFrustum.h"
#include "VoxelSystem.h"
#include "Webcam.h"
#include "renderer/GeometryCache.h"
#include "ui/ChatEntry.h"
class QAction;
@ -89,6 +90,7 @@ public:
bool shouldDynamicallySetJitterBuffer() { return _audioJitterBufferSamples == 0; }
QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
GeometryCache* getGeometryCache() { return &_geometryCache; }
private slots:
@ -318,6 +320,8 @@ private:
int _scaleInLocation;
int _hmdWarpParamLocation;
GeometryCache _geometryCache;
#ifndef _WIN32
Audio _audio;
#endif

View file

@ -27,7 +27,8 @@ const float EAR_RIGHT_OFFSET = 1.0;
const float MOUTH_UP_OFFSET = -0.3f;
const float HEAD_MOTION_DECAY = 0.1;
const float MINIMUM_EYE_ROTATION_DOT = 0.5f; // based on a dot product: 1.0 is straight ahead, 0.0 is 90 degrees off
const float EYEBALL_RADIUS = 0.017;
const float EYEBALL_RADIUS = 0.017;
const float EYELID_RADIUS = 0.019;
const float EYEBALL_COLOR[3] = { 0.9f, 0.9f, 0.8f };
const float HAIR_SPRING_FORCE = 10.0f;
const float HAIR_TORQUE_FORCE = 0.1f;
@ -71,7 +72,11 @@ Head::Head(Avatar* owningAvatar) :
_mohawkTriangleFan(NULL),
_mohawkColors(NULL),
_saccade(0.0f, 0.0f, 0.0f),
_saccadeTarget(0.0f, 0.0f, 0.0f)
_saccadeTarget(0.0f, 0.0f, 0.0f),
_leftEyeBlink(0.0f),
_rightEyeBlink(0.0f),
_leftEyeBlinkVelocity(0.0f),
_rightEyeBlinkVelocity(0.0f)
{
if (USING_PHYSICAL_MOHAWK) {
resetHairPhysics();
@ -162,6 +167,31 @@ void Head::simulate(float deltaTime, bool isMine) {
_browAudioLift *= 0.7f;
// update eyelid blinking
if (_leftEyeBlinkVelocity == 0.0f && _rightEyeBlinkVelocity == 0.0f) {
const float BLINK_INTERVAL = 4.0f;
if (shouldDo(BLINK_INTERVAL, deltaTime)) {
_leftEyeBlinkVelocity = 5.0f;
_rightEyeBlinkVelocity = 5.0f;
}
} else {
_leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, 0.0f, 1.0f);
_rightEyeBlink = glm::clamp(_rightEyeBlink + _rightEyeBlinkVelocity * deltaTime, 0.0f, 1.0f);
if (_leftEyeBlink == 1.0f) {
_leftEyeBlinkVelocity = -5.0f;
} else if (_leftEyeBlink == 0.0f) {
_leftEyeBlinkVelocity = 0.0f;
}
if (_rightEyeBlink == 1.0f) {
_rightEyeBlinkVelocity = -5.0f;
} else if (_rightEyeBlink == 0.0f) {
_rightEyeBlinkVelocity = 0.0f;
}
}
// based on the nature of the lookat position, determine if the eyes can look / are looking at it.
if (USING_PHYSICAL_MOHAWK) {
updateHairPhysics(deltaTime);
@ -534,6 +564,37 @@ void Head::renderEyeBalls() {
_irisProgram->release();
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glEnable(GL_RESCALE_NORMAL);
glColor4f(_skinColor.x, _skinColor.y, _skinColor.z, _renderAlpha);
// left eyelid
glPushMatrix(); {
glTranslatef(_leftEyePosition.x, _leftEyePosition.y, _leftEyePosition.z); //translate to eyeball position
glm::vec3 rotationAxis = glm::axis(orientation);
glRotatef(glm::angle(orientation), rotationAxis.x, rotationAxis.y, rotationAxis.z);
glScalef(EYELID_RADIUS, EYELID_RADIUS, EYELID_RADIUS);
glRotatef(-90 * _leftEyeBlink, 1, 0, 0);
Application::getInstance()->getGeometryCache()->renderHemisphere(15, 10);
glRotatef(180 * _leftEyeBlink, 1, 0, 0);
Application::getInstance()->getGeometryCache()->renderHemisphere(15, 10);
}
glPopMatrix();
// right eyelid
glPushMatrix(); {
glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); //translate to eyeball position
glm::vec3 rotationAxis = glm::axis(orientation);
glRotatef(glm::angle(orientation), rotationAxis.x, rotationAxis.y, rotationAxis.z);
glScalef(EYELID_RADIUS, EYELID_RADIUS, EYELID_RADIUS);
glRotatef(-90 * _rightEyeBlink, 1, 0, 0);
Application::getInstance()->getGeometryCache()->renderHemisphere(15, 10);
glRotatef(180 * _rightEyeBlink, 1, 0, 0);
Application::getInstance()->getGeometryCache()->renderHemisphere(15, 10);
}
glPopMatrix();
glDisable(GL_RESCALE_NORMAL);
}
void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {

View file

@ -106,6 +106,10 @@ private:
glm::vec3* _mohawkColors;
glm::vec3 _saccade;
glm::vec3 _saccadeTarget;
float _leftEyeBlink;
float _rightEyeBlink;
float _leftEyeBlinkVelocity;
float _rightEyeBlinkVelocity;
static ProgramObject* _irisProgram;
static GLuint _irisTextureID;

View file

@ -0,0 +1,101 @@
//
// GeometryCache.cpp
// interface
//
// Created by Andrzej Kapolka on 6/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <cmath>
#include "GeometryCache.h"
#include "world.h"
GeometryCache::~GeometryCache() {
foreach (const VerticesIndices& vbo, _hemisphereVBOs) {
glDeleteBuffers(1, &vbo.first);
glDeleteBuffers(1, &vbo.second);
}
}
void GeometryCache::renderHemisphere(int slices, int stacks) {
VerticesIndices& vbo = _hemisphereVBOs[SlicesStacks(slices, stacks)];
int vertices = slices * (stacks - 1) + 1;
int indices = slices * 2 * 3 * (stacks - 2) + slices * 3;
if (vbo.first == 0) {
GLfloat* vertexData = new GLfloat[vertices * 3];
GLfloat* vertex = vertexData;
for (int i = 0; i < stacks - 1; i++) {
float phi = PIf * 0.5f * i / (stacks - 1), z, radius;
sincosf(phi, &z, &radius);
for (int j = 0; j < slices; j++) {
float theta = PIf * 2.0f * j / slices;
float x, y;
sincosf(theta, &x, &y);
x *= radius;
y *= radius;
*(vertex++) = x;
*(vertex++) = y;
*(vertex++) = z;
}
}
*(vertex++) = 0.0f;
*(vertex++) = 0.0f;
*(vertex++) = 1.0f;
glGenBuffers(1, &vbo.first);
glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
const int BYTES_PER_VERTEX = 3 * sizeof(GLfloat);
glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
delete[] vertexData;
GLushort* indexData = new GLushort[indices];
GLushort* index = indexData;
for (int i = 0; i < stacks - 2; i++) {
GLushort bottom = i * slices;
GLushort top = bottom + slices;
for (int j = 0; j < slices; j++) {
int next = (j + 1) % slices;
*(index++) = bottom + j;
*(index++) = top + next;
*(index++) = top + j;
*(index++) = bottom + j;
*(index++) = bottom + next;
*(index++) = top + next;
}
}
GLushort bottom = (stacks - 2) * slices;
GLushort top = bottom + slices;
for (int i = 0; i < slices; i++) {
*(index++) = bottom + i;
*(index++) = bottom + (i + 1) % slices;
*(index++) = top;
}
glGenBuffers(1, &vbo.second);
glBindBuffer(GL_ARRAY_BUFFER, vbo.second);
const int BYTES_PER_INDEX = sizeof(GLushort);
glBufferData(GL_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
delete[] indexData;
} else {
glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
glNormalPointer(GL_FLOAT, 0, 0);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

View file

@ -0,0 +1,31 @@
//
// GeometryCache.h
// interface
//
// Created by Andrzej Kapolka on 6/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__GeometryCache__
#define __interface__GeometryCache__
#include <QHash>
#include "InterfaceConfig.h"
class GeometryCache {
public:
~GeometryCache();
void renderHemisphere(int slices, int stacks);
private:
typedef QPair<int, int> SlicesStacks;
typedef QPair<GLuint, GLuint> VerticesIndices;
QHash<SlicesStacks, VerticesIndices> _hemisphereVBOs;
};
#endif /* defined(__interface__GeometryCache__) */