From 91999dfe1f3b14c81036d336f58720a13c0a63b9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 26 Sep 2013 15:48:11 -0700 Subject: [PATCH] Pupil dilation. --- interface/src/Menu.cpp | 7 +++++ interface/src/avatar/Avatar.cpp | 2 ++ interface/src/avatar/BlendFace.cpp | 8 ++--- interface/src/avatar/BlendFace.h | 5 ++- interface/src/avatar/Head.cpp | 18 +++++------ interface/src/avatar/Head.h | 5 ++- interface/src/avatar/PerlinFace.cpp | 6 +++- interface/src/renderer/TextureCache.cpp | 41 +++++++++++++++++++++++++ interface/src/renderer/TextureCache.h | 36 ++++++++++++++++++++++ libraries/avatars/src/AvatarData.cpp | 8 ++++- libraries/avatars/src/HeadData.h | 4 +++ libraries/shared/src/PacketHeaders.cpp | 2 +- 12 files changed, 123 insertions(+), 19 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 560f72807b..77d00c393b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "Application.h" @@ -749,6 +750,10 @@ void Menu::editPreferences() { faceURL->setMinimumWidth(QLINE_MINIMUM_WIDTH); form->addRow("Face URL:", faceURL); + QSlider* pupilDilation = new QSlider(Qt::Horizontal); + pupilDilation->setValue(applicationInstance->getAvatar()->getHead().getPupilDilation() * pupilDilation->maximum()); + form->addRow("Pupil Dilation:", pupilDilation); + QSpinBox* fieldOfView = new QSpinBox(); fieldOfView->setMaximum(180); fieldOfView->setMinimum(1); @@ -790,6 +795,8 @@ void Menu::editPreferences() { Avatar::sendAvatarURLsMessage(avatarVoxelURL, faceModelURL); + applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum()); + _gyroCameraSensitivity = gyroCameraSensitivity->value(); applicationInstance->getAvatar()->setLeanScale(leanScale->value()); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8aba7f8b4d..028bfef2ef 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -770,6 +770,7 @@ void Avatar::loadData(QSettings* settings) { _voxels.setVoxelURL(settings->value("voxelURL").toUrl()); _head.getBlendFace().setModelURL(settings->value("faceModelURL").toUrl()); + _head.setPupilDilation(settings->value("pupilDilation", 0.0f).toFloat()); _leanScale = loadSetting(settings, "leanScale", 0.05f); @@ -822,6 +823,7 @@ void Avatar::saveData(QSettings* set) { set->setValue("voxelURL", _voxels.getVoxelURL()); set->setValue("faceModelURL", _head.getBlendFace().getModelURL()); + set->setValue("pupilDilation", _head.getPupilDilation()); set->setValue("leanScale", _leanScale); set->setValue("scale", _newScale); diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index bb31437a1d..e531052726 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -28,7 +28,7 @@ BlendFace::~BlendFace() { } ProgramObject BlendFace::_eyeProgram; -GLuint BlendFace::_eyeTextureID; +DilatedTextureCache BlendFace::_eyeTextureCache("resources/images/eye.png", 50, 210); void BlendFace::init() { if (!_eyeProgram.isLinked()) { @@ -40,8 +40,6 @@ void BlendFace::init() { _eyeProgram.bind(); _eyeProgram.setUniformValue("texture", 0); _eyeProgram.release(); - - _eyeTextureID = Application::getInstance()->getTextureCache()->getFileTextureID("resources/images/eye.png"); } } @@ -92,7 +90,9 @@ bool BlendFace::render(float alpha) { // use texture coordinates only for the eye, for now glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glBindTexture(GL_TEXTURE_2D, _eyeTextureID); + _eyeTexture = _eyeTextureCache.getTexture(_owningHead->getPupilDilation()); + glBindTexture(GL_TEXTURE_2D, _eyeTexture->getID()); + glEnable(GL_TEXTURE_2D); _eyeProgram.bind(); diff --git a/interface/src/avatar/BlendFace.h b/interface/src/avatar/BlendFace.h index 8e7302a729..47b3caf758 100644 --- a/interface/src/avatar/BlendFace.h +++ b/interface/src/avatar/BlendFace.h @@ -15,6 +15,7 @@ #include "InterfaceConfig.h" #include "renderer/FBXReader.h" #include "renderer/ProgramObject.h" +#include "renderer/TextureCache.h" class QNetworkReply; @@ -62,8 +63,10 @@ private: QVector _blendedVertices; QVector _blendedNormals; + QSharedPointer _eyeTexture; + static ProgramObject _eyeProgram; - static GLuint _eyeTextureID; + static DilatedTextureCache _eyeTextureCache; }; #endif /* defined(__interface__BlendFace__) */ diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 2e17ad3557..6e437780e9 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -29,7 +29,7 @@ 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 = 15.0f; +const float HAIR_SPRING_FORCE = 15.0f; const float HAIR_TORQUE_FORCE = 0.2f; const float HAIR_GRAVITY_FORCE = 0.001f; const float HAIR_DRAG = 10.0f; @@ -46,7 +46,7 @@ const float IRIS_PROTRUSION = 0.0145f; const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png"; ProgramObject Head::_irisProgram; -GLuint Head::_irisTextureID; +DilatedTextureCache Head::_irisTextureCache(IRIS_TEXTURE_FILENAME, 53, 127); int Head::_eyePositionLocation; Head::Head(Avatar* owningAvatar) : @@ -102,13 +102,6 @@ void Head::init() { _irisProgram.setUniformValue("texture", 0); _eyePositionLocation = _irisProgram.uniformLocation("eyePosition"); - - _irisTextureID = Application::getInstance()->getTextureCache()->getFileTextureID(IRIS_TEXTURE_FILENAME); - - glBindTexture(GL_TEXTURE_2D, _irisTextureID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glBindTexture(GL_TEXTURE_2D, 0); } _blendFace.init(); } @@ -667,7 +660,12 @@ void Head::renderEyeBalls() { glPopMatrix(); _irisProgram.bind(); - glBindTexture(GL_TEXTURE_2D, _irisTextureID); + + _irisTexture = _irisTextureCache.getTexture(_pupilDilation); + glBindTexture(GL_TEXTURE_2D, _irisTexture->getID()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glEnable(GL_TEXTURE_2D); // render left iris diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 4c535edcba..ab07227fc6 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -24,6 +24,7 @@ #include "PerlinFace.h" #include "world.h" #include "devices/SerialInterface.h" +#include "renderer/TextureCache.h" enum eyeContactTargets { LEFT_EYE, @@ -135,8 +136,10 @@ private: PerlinFace _perlinFace; BlendFace _blendFace; + QSharedPointer _irisTexture; + static ProgramObject _irisProgram; - static GLuint _irisTextureID; + static DilatedTextureCache _irisTextureCache; static int _eyePositionLocation; // private methods diff --git a/interface/src/avatar/PerlinFace.cpp b/interface/src/avatar/PerlinFace.cpp index 41641673af..5784c51e67 100644 --- a/interface/src/avatar/PerlinFace.cpp +++ b/interface/src/avatar/PerlinFace.cpp @@ -248,7 +248,11 @@ void PerlinFace::render() { Head::_irisProgram.bind(); - glBindTexture(GL_TEXTURE_2D, Head::_irisTextureID); + _owningHead->_irisTexture = Head::_irisTextureCache.getTexture(_owningHead->_pupilDilation); + glBindTexture(GL_TEXTURE_2D, _owningHead->_irisTexture->getID()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glEnable(GL_TEXTURE_2D); orientation = _owningHead->getOrientation(); diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 3d04a828fc..ebb9c77890 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -154,3 +154,44 @@ QOpenGLFramebufferObject* TextureCache::createFramebufferObject() { return fbo; } + +Texture::Texture() { + glGenTextures(1, &_id); +} + +Texture::~Texture() { + glDeleteTextures(1, &_id); +} + +DilatedTextureCache::DilatedTextureCache(const QString& filename, int innerRadius, int outerRadius) : + _innerRadius(innerRadius), + _outerRadius(outerRadius) +{ + switchToResourcesParentIfRequired(); + _image = QImage(filename).convertToFormat(QImage::Format_ARGB32); +} + +QSharedPointer DilatedTextureCache::getTexture(float dilation) { + QSharedPointer texture = _textures.value(dilation); + if (texture.isNull()) { + texture = QSharedPointer(new Texture()); + + QImage dilatedImage = _image; + QPainter painter; + painter.begin(&dilatedImage); + QPainterPath path; + qreal radius = glm::mix(_innerRadius, _outerRadius, dilation); + path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius); + painter.fillPath(path, Qt::black); + painter.end(); + + glBindTexture(GL_TEXTURE_2D, texture->getID()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 1, + GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + + _textures.insert(dilation, texture); + } + return texture; +} diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index a970b1373c..11a847d838 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -10,7 +10,11 @@ #define __interface__TextureCache__ #include +#include +#include #include +#include +#include #include "InterfaceConfig.h" @@ -62,4 +66,36 @@ private: QOpenGLFramebufferObject* _tertiaryFramebufferObject; }; +/// A simple object wrapper for an OpenGL texture. +class Texture { +public: + + Texture(); + ~Texture(); + + GLuint getID() const { return _id; } + +private: + + GLuint _id; +}; + +/// Caches textures according to pupillary dilation. +class DilatedTextureCache { +public: + + DilatedTextureCache(const QString& filename, int innerRadius, int outerRadius); + + /// Returns a pointer to a texture with the requested amount of dilation. + QSharedPointer getTexture(float dilation); + +private: + + QImage _image; + int _innerRadius; + int _outerRadius; + + QMap > _textures; +}; + #endif /* defined(__interface__TextureCache__) */ diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index dab3d1651e..edc76bedca 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -211,6 +211,9 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float); } + // pupil dilation + destinationBuffer += packFloatToByte(destinationBuffer, _headData->_pupilDilation, 1.0f); + // leap hand data destinationBuffer += _handData->encodeRemoteData(destinationBuffer); @@ -345,7 +348,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { _headData->_blendshapeCoefficients.size() * sizeof(float)); sourceBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float); } - + + // pupil dilation + sourceBuffer += unpackFloatFromByte(sourceBuffer, _headData->_pupilDilation, 1.0f); + // leap hand data if (sourceBuffer - startPosition < numBytes) { // check passed, bytes match diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index 88895a58f6..0f096059c0 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -46,6 +46,9 @@ public: const std::vector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + float getPupilDilation() const { return _pupilDilation; } + void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; } + void addYaw(float yaw); void addPitch(float pitch); void addRoll(float roll); @@ -70,6 +73,7 @@ protected: float _averageLoudness; float _browAudioLift; std::vector _blendshapeCoefficients; + float _pupilDilation; AvatarData* _owningAvatar; private: diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index c3e67fb10f..1d5eb3f5d4 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -20,7 +20,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { return 1; case PACKET_TYPE_HEAD_DATA: - return 7; + return 8; case PACKET_TYPE_AVATAR_URLS: return 1;