From ef7c6ebdc6c5fc6634e04ba175f314a43dc72377 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 21 Jun 2013 18:11:31 -0700 Subject: [PATCH 1/3] Basic blinking. --- interface/src/Application.h | 4 + interface/src/Head.cpp | 65 ++++++++++++++- interface/src/Head.h | 4 + interface/src/renderer/GeometryCache.cpp | 101 +++++++++++++++++++++++ interface/src/renderer/GeometryCache.h | 31 +++++++ 5 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 interface/src/renderer/GeometryCache.cpp create mode 100644 interface/src/renderer/GeometryCache.h diff --git a/interface/src/Application.h b/interface/src/Application.h index f84ff6c20a..8667e68356 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -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 diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index aebb8837a5..7bb97d8426 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -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) { diff --git a/interface/src/Head.h b/interface/src/Head.h index 840954b0b9..a41b836eda 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -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; diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp new file mode 100644 index 0000000000..c2321c5f51 --- /dev/null +++ b/interface/src/renderer/GeometryCache.cpp @@ -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 + +#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); +} diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h new file mode 100644 index 0000000000..0c5ccea06f --- /dev/null +++ b/interface/src/renderer/GeometryCache.h @@ -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 + +#include "InterfaceConfig.h" + +class GeometryCache { +public: + + ~GeometryCache(); + + void renderHemisphere(int slices, int stacks); + +private: + + typedef QPair SlicesStacks; + typedef QPair VerticesIndices; + + QHash _hemisphereVBOs; +}; + +#endif /* defined(__interface__GeometryCache__) */ From 1e258aae9928d17f81d25485e357eeb05405249b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 24 Jun 2013 10:20:01 -0700 Subject: [PATCH 2/3] Define blink speed as a constant. --- interface/src/Head.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 7bb97d8426..e2e5efcb9a 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -168,24 +168,25 @@ void Head::simulate(float deltaTime, bool isMine) { _browAudioLift *= 0.7f; // update eyelid blinking + const float BLINK_SPEED = 5.0f; if (_leftEyeBlinkVelocity == 0.0f && _rightEyeBlinkVelocity == 0.0f) { const float BLINK_INTERVAL = 4.0f; if (shouldDo(BLINK_INTERVAL, deltaTime)) { - _leftEyeBlinkVelocity = 5.0f; - _rightEyeBlinkVelocity = 5.0f; + _leftEyeBlinkVelocity = BLINK_SPEED; + _rightEyeBlinkVelocity = BLINK_SPEED; } } 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; + _leftEyeBlinkVelocity = -BLINK_SPEED; } else if (_leftEyeBlink == 0.0f) { _leftEyeBlinkVelocity = 0.0f; } if (_rightEyeBlink == 1.0f) { - _rightEyeBlinkVelocity = -5.0f; + _rightEyeBlinkVelocity = -BLINK_SPEED; } else if (_rightEyeBlink == 0.0f) { _rightEyeBlinkVelocity = 0.0f; From a0ecd167fce716adc39d5a997fb4060eda5b1d18 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 24 Jun 2013 10:31:11 -0700 Subject: [PATCH 3/3] Replace 0/1 with FULLY_OPEN/CLOSED. --- interface/src/Head.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index e2e5efcb9a..61b4ca96b9 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -169,6 +169,8 @@ void Head::simulate(float deltaTime, bool isMine) { // update eyelid blinking const float BLINK_SPEED = 5.0f; + const float FULLY_OPEN = 0.0f; + const float FULLY_CLOSED = 1.0f; if (_leftEyeBlinkVelocity == 0.0f && _rightEyeBlinkVelocity == 0.0f) { const float BLINK_INTERVAL = 4.0f; if (shouldDo(BLINK_INTERVAL, deltaTime)) { @@ -176,19 +178,19 @@ void Head::simulate(float deltaTime, bool isMine) { _rightEyeBlinkVelocity = BLINK_SPEED; } } else { - _leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, 0.0f, 1.0f); - _rightEyeBlink = glm::clamp(_rightEyeBlink + _rightEyeBlinkVelocity * deltaTime, 0.0f, 1.0f); + _leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED); + _rightEyeBlink = glm::clamp(_rightEyeBlink + _rightEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED); - if (_leftEyeBlink == 1.0f) { + if (_leftEyeBlink == FULLY_CLOSED) { _leftEyeBlinkVelocity = -BLINK_SPEED; - } else if (_leftEyeBlink == 0.0f) { + } else if (_leftEyeBlink == FULLY_OPEN) { _leftEyeBlinkVelocity = 0.0f; } - if (_rightEyeBlink == 1.0f) { + if (_rightEyeBlink == FULLY_CLOSED) { _rightEyeBlinkVelocity = -BLINK_SPEED; - } else if (_rightEyeBlink == 0.0f) { + } else if (_rightEyeBlink == FULLY_OPEN) { _rightEyeBlinkVelocity = 0.0f; } }