diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4edaa74325..998c6e32e7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2254,7 +2254,7 @@ Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3 if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar* avatar = (Avatar *) node->getLinkedData(); glm::vec3 headPosition = avatar->getHead().getPosition(); - if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS)) { + if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS * avatar->getScale())) { eyePosition = avatar->getHead().getEyePosition(); _lookatIndicatorScale = avatar->getScale(); _lookatOtherPosition = headPosition; @@ -2266,6 +2266,16 @@ Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3 return NULL; } +bool Application::isLookingAtMyAvatar(Avatar* avatar) { + glm::vec3 theirLookat = avatar->getHead().getLookAtPosition(); + glm::vec3 myHeadPosition = _myAvatar.getHead().getPosition(); + + if (pointInSphere(theirLookat, myHeadPosition, HEAD_SPHERE_RADIUS * _myAvatar.getScale())) { + return true; + } + return false; +} + void Application::renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera) { const float DISTANCE_FROM_HEAD_SPHERE = 0.1f * _lookatIndicatorScale; @@ -3015,6 +3025,9 @@ void Application::displaySide(Camera& whichCamera) { if (!avatar->isInitialized()) { avatar->init(); } + if (isLookingAtMyAvatar(avatar)) { + avatar->getHead().setLookAtPosition(_myCamera.getPosition()); + } avatar->render(false, _renderAvatarBalls->isChecked()); avatar->setDisplayingLookatVectors(_renderLookatOn->isChecked()); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 5987a13900..cb851c1dfc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -213,6 +213,7 @@ private: void update(float deltaTime); Avatar* isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, glm::vec3& eyePosition, uint16_t& nodeID); + bool isLookingAtMyAvatar(Avatar* avatar); void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera); void updateAvatar(float deltaTime); diff --git a/interface/src/BendyLine.cpp b/interface/src/BendyLine.cpp new file mode 100644 index 0000000000..ef5bd5f18d --- /dev/null +++ b/interface/src/BendyLine.cpp @@ -0,0 +1,119 @@ +// +// BendyLine.cpp +// interface +// +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include "BendyLine.h" +#include "Util.h" +#include "world.h" + +const float DEFAULT_BENDY_LINE_SPRING_FORCE = 10.0f; +const float DEFAULT_BENDY_LINE_TORQUE_FORCE = 0.1f; +const float DEFAULT_BENDY_LINE_DRAG = 10.0f; +const float DEFAULT_BENDY_LINE_LENGTH = 0.09f; +const float DEFAULT_BENDY_LINE_THICKNESS = 0.03f; + +BendyLine::BendyLine(){ + + _springForce = DEFAULT_BENDY_LINE_SPRING_FORCE; + _torqueForce = DEFAULT_BENDY_LINE_TORQUE_FORCE; + _drag = DEFAULT_BENDY_LINE_DRAG; + _length = DEFAULT_BENDY_LINE_LENGTH; + _thickness = DEFAULT_BENDY_LINE_THICKNESS; + + _gravityForce = glm::vec3(0.0f, 0.0f, 0.0f); + _basePosition = glm::vec3(0.0f, 0.0f, 0.0f); + _baseDirection = glm::vec3(0.0f, 0.0f, 0.0f); + _midPosition = glm::vec3(0.0f, 0.0f, 0.0f); + _endPosition = glm::vec3(0.0f, 0.0f, 0.0f); + _midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + _endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); +} + +void BendyLine::reset() { + + _midPosition = _basePosition + _baseDirection * _length * ONE_HALF; + _endPosition = _midPosition + _baseDirection * _length * ONE_HALF; + _midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + _endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); +} + +void BendyLine::update(float deltaTime) { + + glm::vec3 midAxis = _midPosition - _basePosition; + glm::vec3 endAxis = _endPosition - _midPosition; + + float midLength = glm::length(midAxis); + float endLength = glm::length(endAxis); + + glm::vec3 midDirection; + glm::vec3 endDirection; + + if (midLength > 0.0f) { + midDirection = midAxis / midLength; + } else { + midDirection = _baseDirection; + } + + if (endLength > 0.0f) { + endDirection = endAxis / endLength; + } else { + endDirection = _baseDirection; + } + + // add spring force + float midForce = midLength - _length * ONE_HALF; + float endForce = endLength - _length * ONE_HALF; + _midVelocity -= midDirection * midForce * _springForce * deltaTime; + _endVelocity -= endDirection * endForce * _springForce * deltaTime; + + // add gravity force + _midVelocity += _gravityForce; + _endVelocity += _gravityForce; + + // add torque force + _midVelocity += _baseDirection * _torqueForce * deltaTime; + _endVelocity += midDirection * _torqueForce * deltaTime; + + // add drag force + float momentum = 1.0f - (_drag * deltaTime); + if (momentum < 0.0f) { + _midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + _endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + } else { + _midVelocity *= momentum; + _endVelocity *= momentum; + } + + // update position by velocity + _midPosition += _midVelocity; + _endPosition += _endVelocity; + + // clamp lengths + glm::vec3 newMidVector = _midPosition - _basePosition; + glm::vec3 newEndVector = _endPosition - _midPosition; + + float newMidLength = glm::length(newMidVector); + float newEndLength = glm::length(newEndVector); + + glm::vec3 newMidDirection; + glm::vec3 newEndDirection; + + if (newMidLength > 0.0f) { + newMidDirection = newMidVector/newMidLength; + } else { + newMidDirection = _baseDirection; + } + + if (newEndLength > 0.0f) { + newEndDirection = newEndVector/newEndLength; + } else { + newEndDirection = _baseDirection; + } + + _endPosition = _midPosition + newEndDirection * _length * ONE_HALF; + _midPosition = _basePosition + newMidDirection * _length * ONE_HALF; +} + + diff --git a/interface/src/BendyLine.h b/interface/src/BendyLine.h new file mode 100644 index 0000000000..47a86595ff --- /dev/null +++ b/interface/src/BendyLine.h @@ -0,0 +1,52 @@ +// +// BendyLine.h +// interface +// +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef hifi_bendyLine_h +#define hifi_bendyLine_h + +#include +#include +#include + +class BendyLine { +public: + BendyLine(); + + void update(float deltaTime); + void reset(); + + void setLength (float length ) { _length = length; } + void setThickness (float thickness ) { _thickness = thickness; } + void setSpringForce (float springForce ) { _springForce = springForce; } + void setTorqueForce (float torqueForce ) { _torqueForce = torqueForce; } + void setDrag (float drag ) { _drag = drag; } + void setBasePosition (glm::vec3 basePosition ) { _basePosition = basePosition; } + void setBaseDirection(glm::vec3 baseDirection) { _baseDirection = baseDirection;} + void setGravityForce (glm::vec3 gravityForce ) { _gravityForce = gravityForce; } + + glm::vec3 getBasePosition() { return _basePosition; } + glm::vec3 getMidPosition () { return _midPosition; } + glm::vec3 getEndPosition () { return _endPosition; } + float getThickness () { return _thickness; } + +private: + + float _springForce; + float _torqueForce; + float _drag; + float _length; + float _thickness; + glm::vec3 _gravityForce; + glm::vec3 _basePosition; + glm::vec3 _baseDirection; + glm::vec3 _midPosition; + glm::vec3 _endPosition; + glm::vec3 _midVelocity; + glm::vec3 _endVelocity; +}; + +#endif diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index fcea8ca270..5aed606191 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -322,27 +322,48 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { // apply color modulation if (myEmitter.particleAttributes[lifeStage ].modulationAmplitude > 0.0f) { - float modulation = 0.0f; + float redModulation = 0.0f; + float greenModulation = 0.0f; + float bueModulation = 0.0f; float radian = _timer * myEmitter.particleAttributes[lifeStage ].modulationRate * PI_TIMES_TWO; + if (myEmitter.particleAttributes[lifeStage ].modulationStyle == COLOR_MODULATION_STYLE_LIGHNTESS_PULSE) { if (sinf(radian) > 0.0f) { - modulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude; + redModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude; + greenModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude; + bueModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude; } + } else if (myEmitter.particleAttributes[lifeStage].modulationStyle == COLOR_MODULATION_STYLE_LIGHTNESS_WAVE) { - float a = myEmitter.particleAttributes[lifeStage].modulationAmplitude; - modulation = a * ONE_HALF + sinf(radian) * a * ONE_HALF; + float amp = myEmitter.particleAttributes[lifeStage].modulationAmplitude; + float brightness = amp * ONE_HALF + sinf(radian) * amp * ONE_HALF; + redModulation = brightness; + greenModulation = brightness; + bueModulation = brightness; + + } else if (myEmitter.particleAttributes[lifeStage].modulationStyle == COLOR_MODULATION_STYLE_RAINBOW_CYCLE) { + + float amp = myEmitter.particleAttributes[lifeStage].modulationAmplitude * ONE_HALF; + redModulation = sinf(radian * RAINBOW_CYCLE_RED_RATE ) * amp; + greenModulation = sinf(radian * RAINBOW_CYCLE_GREEN_RATE) * amp; + bueModulation = sinf(radian * RAINBOW_CYCLE_BLUE_RATE ) * amp; } - _particle[p].color.r += modulation; - _particle[p].color.g += modulation; - _particle[p].color.b += modulation; - _particle[p].color.a += modulation; + _particle[p].color.r += redModulation; + _particle[p].color.g += greenModulation; + _particle[p].color.b += bueModulation; + _particle[p].color.a = 1.0f; if (_particle[p].color.r > 1.0f) {_particle[p].color.r = 1.0f;} if (_particle[p].color.g > 1.0f) {_particle[p].color.g = 1.0f;} if (_particle[p].color.b > 1.0f) {_particle[p].color.b = 1.0f;} if (_particle[p].color.a > 1.0f) {_particle[p].color.a = 1.0f;} - } + + if (_particle[p].color.r < 0.0f) {_particle[p].color.r = 0.0f;} + if (_particle[p].color.g < 0.0f) {_particle[p].color.g = 0.0f;} + if (_particle[p].color.b < 0.0f) {_particle[p].color.b = 0.0f;} + if (_particle[p].color.a < 0.0f) {_particle[p].color.a = 0.0f;} + } // do this at the end... _particle[p].age += deltaTime; diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index a0131883a1..60bd0f91d4 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -15,6 +15,10 @@ const int NULL_PARTICLE = -1; const int MAX_EMITTERS = 100; const int MAX_PARTICLES = 5000; +const float RAINBOW_CYCLE_RED_RATE = 0.5f; +const float RAINBOW_CYCLE_GREEN_RATE = 0.7f; +const float RAINBOW_CYCLE_BLUE_RATE = 1.0f; + enum ParticleRenderStyle { PARTICLE_RENDER_STYLE_SPHERE = 0, @@ -28,6 +32,7 @@ enum ColorModulationStyle COLOR_MODULATION_STYLE_NULL = -1, COLOR_MODULATION_STYLE_LIGHNTESS_PULSE, COLOR_MODULATION_STYLE_LIGHTNESS_WAVE, + COLOR_MODULATION_STYLE_RAINBOW_CYCLE, NUM_COLOR_MODULATION_STYLES }; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 61b9b2d7ca..743957128c 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -607,3 +607,12 @@ bool rayIntersectsSphere(glm::vec3& rayStarting, glm::vec3& rayNormalizedDirecti } return false; } + +bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadius) { + glm::vec3 diff = point - sphereCenter; + double mag = sqrt(glm::dot(diff, diff)); + if (mag <= sphereRadius) { + return true; + } + return false; +} \ No newline at end of file diff --git a/interface/src/Util.h b/interface/src/Util.h index 6fc797e3e3..c1bb2949fa 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -76,4 +76,6 @@ float loadSetting(QSettings* settings, const char* name, float defaultValue); bool rayIntersectsSphere(glm::vec3& rayStarting, glm::vec3& rayNormalizedDirection, glm::vec3& sphereCenter, double sphereRadius); +bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadius); + #endif diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 7b74a1b7d8..bf09096d7f 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -343,29 +343,6 @@ void Hand::updateRaveGloveParticles(float deltaTime) { _raveGloveParticleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); _raveGloveInitialized = true; } else { - - _raveGloveClock += deltaTime; - - // this rave glove effect oscillates though various colors and radii that are meant to show off some effects - if (_raveGloveMode == RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR) { - ParticleSystem::ParticleAttributes attributes; - float red = 0.5f + 0.5f * sinf(_raveGloveClock * 2.4f); - float green = 0.5f + 0.5f * cosf(_raveGloveClock * 2.7f); - float blue = 0.5f + 0.5f * sinf(_raveGloveClock * 3.0f); - float alpha = 1.0f; - - attributes.color = glm::vec4(red, green, blue, alpha); - attributes.radius = 0.01f + 0.003f * sinf(_raveGloveClock * 50.0f); - attributes.modulationAmplitude = 0.0f; - - for ( int f = 0; f< NUM_FINGERS; f ++ ) { - _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_0, attributes); - _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_1, attributes); - _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_2, attributes); - _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_3, attributes); - } - } - _raveGloveParticleSystem.simulate(deltaTime); } } @@ -395,11 +372,15 @@ void Hand::setRaveGloveMode(int mode) { _raveGloveParticleSystem.setParticleAttributesToDefault(&attributes); - attributes.radius = 0.02f; - attributes.gravity = 0.0f; - attributes.airFriction = 0.0f; - attributes.jitter = 0.0f; - attributes.bounce = 0.0f; + attributes.modulationAmplitude = 1.0; + attributes.modulationRate = 0.33; + attributes.modulationStyle = COLOR_MODULATION_STYLE_RAINBOW_CYCLE; + attributes.color = glm::vec4( 0.5f, 0.5f, 0.5f, 1.0f); + attributes.radius = 0.02f; + attributes.gravity = 0.0f; + attributes.airFriction = 0.0f; + attributes.jitter = 0.0f; + attributes.bounce = 0.0f; _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_0, attributes); _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_1, attributes); _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_2, attributes); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 76db8dbca0..b88802b7f1 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -30,9 +30,9 @@ const float MINIMUM_EYE_ROTATION_DOT = 0.5f; // based on a dot product: 1.0 is 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_SPRING_FORCE = 7.0f; const float HAIR_TORQUE_FORCE = 0.1f; -const float HAIR_GRAVITY_FORCE = 0.05f; +const float HAIR_GRAVITY_FORCE = 0.02f; const float HAIR_DRAG = 10.0f; const float HAIR_LENGTH = 0.09f; const float HAIR_THICKNESS = 0.03f; @@ -90,7 +90,7 @@ Head::Head(Avatar* owningAvatar) : _cameraFollowHeadRate(0.0f), _face(this) { - if (USING_PHYSICAL_MOHAWK) { + if (USING_PHYSICAL_MOHAWK) { resetHairPhysics(); } } @@ -105,7 +105,7 @@ void Head::init() { _irisProgram->setUniformValue("texture", 0); _eyePositionLocation = _irisProgram->uniformLocation("eyePosition"); - + QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_ARGB32); glGenTextures(1, &_irisTextureID); @@ -127,20 +127,20 @@ void Head::reset() { } } - - - void Head::resetHairPhysics() { - glm::vec3 up = getUpDirection(); + //glm::vec3 up = getUpDirection(); for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { - - _hairTuft[t].length = _scale * HAIR_LENGTH; - _hairTuft[t].thickness = _scale * HAIR_THICKNESS; - _hairTuft[t].basePosition = _position + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f; - _hairTuft[t].midPosition = _hairTuft[t].basePosition + up * _hairTuft[t].length * ONE_HALF; - _hairTuft[t].endPosition = _hairTuft[t].midPosition + up * _hairTuft[t].length * ONE_HALF; - _hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); - _hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { + + _hairTuft[t].setSpringForce (HAIR_SPRING_FORCE); + _hairTuft[t].setTorqueForce (HAIR_TORQUE_FORCE); + _hairTuft[t].setGravityForce (HAIR_GRAVITY_FORCE * _gravity); + _hairTuft[t].setDrag (HAIR_DRAG); + _hairTuft[t].setLength (_scale * HAIR_LENGTH ); + _hairTuft[t].setThickness (_scale * HAIR_THICKNESS); + _hairTuft[t].setBaseDirection(getUpDirection()); + _hairTuft[t].reset(); + } } } @@ -223,6 +223,7 @@ void Head::simulate(float deltaTime, bool isMine) { // based on the nature of the lookat position, determine if the eyes can look / are looking at it. if (USING_PHYSICAL_MOHAWK) { updateHairPhysics(deltaTime); + } // Update camera pitch and yaw independently from motion of head (for gyro-based interface) @@ -376,17 +377,17 @@ void Head::renderMohawk() { if (USING_PHYSICAL_MOHAWK) { for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { - glm::vec3 baseAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition; - glm::vec3 midAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition; - glm::vec3 viewVector = _hairTuft[t].basePosition - Application::getInstance()->getCamera()->getPosition(); + glm::vec3 baseAxis = _hairTuft[t].getMidPosition() - _hairTuft[t].getBasePosition(); + glm::vec3 midAxis = _hairTuft[t].getEndPosition() - _hairTuft[t].getMidPosition(); + glm::vec3 viewVector = _hairTuft[t].getBasePosition() - Application::getInstance()->getCamera()->getPosition(); glm::vec3 basePerpendicular = glm::normalize(glm::cross(baseAxis, viewVector)); glm::vec3 midPerpendicular = glm::normalize(glm::cross(midAxis, viewVector)); - glm::vec3 base1 = _hairTuft[t].basePosition - basePerpendicular * _hairTuft[t].thickness * ONE_HALF; - glm::vec3 base2 = _hairTuft[t].basePosition + basePerpendicular * _hairTuft[t].thickness * ONE_HALF; - glm::vec3 mid1 = _hairTuft[t].midPosition - midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF; - glm::vec3 mid2 = _hairTuft[t].midPosition + midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF; + glm::vec3 base1 = _hairTuft[t].getBasePosition() - basePerpendicular * _hairTuft[t].getThickness() * ONE_HALF; + glm::vec3 base2 = _hairTuft[t].getBasePosition() + basePerpendicular * _hairTuft[t].getThickness() * ONE_HALF; + glm::vec3 mid1 = _hairTuft[t].getMidPosition() - midPerpendicular * _hairTuft[t].getThickness() * ONE_HALF * ONE_HALF; + glm::vec3 mid2 = _hairTuft[t].getMidPosition() + midPerpendicular * _hairTuft[t].getThickness() * ONE_HALF * ONE_HALF; glColor3f(_mohawkColors[t].x, _mohawkColors[t].y, _mohawkColors[t].z); @@ -399,7 +400,7 @@ void Head::renderMohawk() { glVertex3f(mid2.x, mid2.y, mid2.z ); glVertex3f(mid1.x, mid1.y, mid1.z ); glVertex3f(mid2.x, mid2.y, mid2.z ); - glVertex3f(_hairTuft[t].endPosition.x, _hairTuft[t].endPosition.y, _hairTuft[t].endPosition.z ); + glVertex3f(_hairTuft[t].getEndPosition().x, _hairTuft[t].getEndPosition().y, _hairTuft[t].getEndPosition().z ); glEnd(); } } else { @@ -735,100 +736,17 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi glEnd(); } - void Head::updateHairPhysics(float deltaTime) { - glm::quat orientation = getOrientation(); glm::vec3 up = orientation * IDENTITY_UP; glm::vec3 front = orientation * IDENTITY_FRONT; - for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { - float fraction = (float)t / (float)(NUM_HAIR_TUFTS - 1); - float angle = -20.0f + 40.0f * fraction; - float radian = angle * PI_OVER_180; - glm::vec3 baseDirection - = front * sinf(radian) - + up * cosf(radian); - - _hairTuft[t].basePosition = _position + _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f * baseDirection; - - glm::vec3 midAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition; - glm::vec3 endAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition; - - float midLength = glm::length(midAxis); - float endLength = glm::length(endAxis); - - glm::vec3 midDirection; - glm::vec3 endDirection; - - if (midLength > 0.0f) { - midDirection = midAxis / midLength; - } else { - midDirection = up; - } - - if (endLength > 0.0f) { - endDirection = endAxis / endLength; - } else { - endDirection = up; - } - - // add spring force - float midForce = midLength - _hairTuft[t].length * ONE_HALF; - float endForce = endLength - _hairTuft[t].length * ONE_HALF; - _hairTuft[t].midVelocity -= midDirection * midForce * HAIR_SPRING_FORCE * deltaTime; - _hairTuft[t].endVelocity -= endDirection * endForce * HAIR_SPRING_FORCE * deltaTime; - - // add gravity force - glm::vec3 gravityForce = _gravity * HAIR_GRAVITY_FORCE * deltaTime; - _hairTuft[t].midVelocity += gravityForce; - _hairTuft[t].endVelocity += gravityForce; - - // add torque force - _hairTuft[t].midVelocity += baseDirection * HAIR_TORQUE_FORCE * deltaTime; - _hairTuft[t].endVelocity += midDirection * HAIR_TORQUE_FORCE * deltaTime; - - // add drag force - float momentum = 1.0f - (HAIR_DRAG * deltaTime); - if (momentum < 0.0f) { - _hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); - _hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); - } else { - _hairTuft[t].midVelocity *= momentum; - _hairTuft[t].endVelocity *= momentum; - } - - // update position by velocity - _hairTuft[t].midPosition += _hairTuft[t].midVelocity; - _hairTuft[t].endPosition += _hairTuft[t].endVelocity; - - // clamp lengths - glm::vec3 newMidVector = _hairTuft[t].midPosition - _hairTuft[t].basePosition; - glm::vec3 newEndVector = _hairTuft[t].endPosition - _hairTuft[t].midPosition; - - float newMidLength = glm::length(newMidVector); - float newEndLength = glm::length(newEndVector); - - glm::vec3 newMidDirection; - glm::vec3 newEndDirection; - - if (newMidLength > 0.0f) { - newMidDirection = newMidVector/newMidLength; - } else { - newMidDirection = up; - } - - if (newEndLength > 0.0f) { - newEndDirection = newEndVector/newEndLength; - } else { - newEndDirection = up; - } - - _hairTuft[t].endPosition = _hairTuft[t].midPosition + newEndDirection * _hairTuft[t].length * ONE_HALF; - _hairTuft[t].midPosition = _hairTuft[t].basePosition + newMidDirection * _hairTuft[t].length * ONE_HALF; + glm::vec3 baseDirection = front * sinf(radian) + up * cosf(radian); + _hairTuft[t].setBasePosition (_position + _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f * baseDirection); + _hairTuft[t].setBaseDirection(baseDirection); + _hairTuft[t].update(deltaTime); } } - diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 3efa742465..1256b05bb7 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -18,6 +18,7 @@ #include #include "Face.h" +#include "BendyLine.h" #include "InterfaceConfig.h" #include "SerialInterface.h" #include "world.h" @@ -29,7 +30,7 @@ enum eyeContactTargets MOUTH }; -const int NUM_HAIR_TUFTS = 4; +const int NUM_HAIR_TUFTS = 4; class Avatar; class ProgramObject; @@ -80,18 +81,6 @@ private: Head(const Head&); Head& operator= (const Head&); - struct HairTuft - { - float length; - float thickness; - - glm::vec3 basePosition; - glm::vec3 midPosition; - glm::vec3 endPosition; - glm::vec3 midVelocity; - glm::vec3 endVelocity; - }; - struct Nose { glm::vec3 top; @@ -123,7 +112,7 @@ private: float _returnSpringScale; //strength of return springs glm::vec3 _bodyRotation; bool _renderLookatVectors; - HairTuft _hairTuft[NUM_HAIR_TUFTS]; + BendyLine _hairTuft[NUM_HAIR_TUFTS]; glm::vec3* _mohawkTriangleFan; glm::vec3* _mohawkColors; glm::vec3 _saccade;