From b74ceae61ae25bb7220ceb4954ee1acf9cafdc89 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Thu, 23 May 2013 22:52:43 -0700 Subject: [PATCH 1/4] added avatar hair --- interface/src/Application.cpp | 4 +- interface/src/Avatar.cpp | 11 ++- interface/src/Avatar.h | 3 +- interface/src/Head.cpp | 167 +++++++++++++++++++++++++++++++++- interface/src/Head.h | 18 +++- 5 files changed, 192 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b9b0948490..c4db1bd71d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1707,13 +1707,13 @@ void Application::displaySide(Camera& whichCamera) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { Avatar *avatar = (Avatar *)agent->getLinkedData(); - avatar->render(false); + avatar->render(false, _myCamera.getPosition()); } } agentList->unlock(); // Render my own Avatar - _myAvatar.render(_lookingInMirror->isChecked()); + _myAvatar.render(_lookingInMirror->isChecked(), _myCamera.getPosition()); _myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked()); } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index bdfd7c8691..a48e4e9b48 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -79,6 +79,7 @@ Avatar::Avatar(bool isMine) : _bodyRollDelta(0.0f), _movedHandOffset(0.0f, 0.0f, 0.0f), _rotation(0.0f, 0.0f, 0.0f, 0.0f), + _cameraPosition(0.0f, 0.0f, 0.0f), _mode(AVATAR_MODE_STANDING), _handHoldingPosition(0.0f, 0.0f, 0.0f), _velocity(0.0f, 0.0f, 0.0f), @@ -725,7 +726,9 @@ void Avatar::setGravity(glm::vec3 gravity) { _head.setGravity(_gravity); } -void Avatar::render(bool lookingInMirror) { +void Avatar::render(bool lookingInMirror, glm::vec3 cameraPosition) { + + _cameraPosition = cameraPosition; if (_isMine && usingBigSphereCollisionTest) { // show TEST big sphere @@ -745,7 +748,7 @@ void Avatar::render(bool lookingInMirror) { // if this is my avatar, then render my interactions with the other avatar if (_isMine) { - _avatarTouch.render(getCameraPosition()); + _avatarTouch.render(_cameraPosition); } // Render the balls @@ -1132,11 +1135,11 @@ void Avatar::renderBody(bool lookingInMirror) { // Render the body as balls and cones for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { - float distanceToCamera = glm::length(getCameraPosition() - _joint[b].position); + float distanceToCamera = glm::length(_cameraPosition - _joint[b].position); // Always render other people, and render myself when beyond threshold distance if (b == AVATAR_JOINT_HEAD_BASE) { // the head is rendered as a special case if (lookingInMirror || !_isMine || distanceToCamera > RENDER_OPAQUE_BEYOND) { - _head.render(lookingInMirror); + _head.render(lookingInMirror, _cameraPosition); } } else if (!_isMine || distanceToCamera > RENDER_TRANSLUCENT_BEYOND) { // Render the sphere at the joint diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 59f9018af3..964a0a04f6 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -107,7 +107,7 @@ public: Head& getHead() { return _head; } void setMousePressed(bool pressed); - void render(bool lookingInMirror); + void render(bool lookingInMirror, glm::vec3 cameraPosition); void renderBody(bool lookingInMirror); void simulate(float deltaTime, Transmitter* transmitter); void setMovedHandOffset(glm::vec3 movedHandOffset) { _movedHandOffset = movedHandOffset; } @@ -162,6 +162,7 @@ private: glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion AvatarJoint _joint[ NUM_AVATAR_JOINTS ]; AvatarMode _mode; + glm::vec3 _cameraPosition; glm::vec3 _handHoldingPosition; glm::vec3 _velocity; glm::vec3 _thrust; diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index cb42c6cc54..c29145774d 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -21,6 +21,13 @@ 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_COLOR[3] = { 0.9f, 0.9f, 0.8f }; +const float HAIR_COLOR[3] = { 0.8f, 0.6f, 0.5f }; +const float HAIR_SPRING_FORCE = 10.0f; +const float HAIR_TORQUE_FORCE = 0.1f; +const float HAIR_GRAVITY_FORCE = 0.05f; +const float HAIR_DRAG = 10.0f; +const float HAIR_LENGTH = 0.06f; +const float HAIR_THICKNESS = 0.02f; const float IRIS_RADIUS = 0.007; const float IRIS_PROTRUSION = 0.0145f; const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png"; @@ -55,14 +62,31 @@ Head::Head() : _bodyRotation(0.0f, 0.0f, 0.0f), _headRotation(0.0f, 0.0f, 0.0f), _renderLookatVectors(false) { + + for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { + _hairTuft[t].length = HAIR_LENGTH; + _hairTuft[t].thickness = HAIR_THICKNESS; + _hairTuft[t].basePosition = glm::vec3(0.0f, 0.0f, 0.0f); + _hairTuft[t].midPosition = glm::vec3(0.0f, 0.0f, 0.0f); + _hairTuft[t].endPosition = glm::vec3(0.0f, 0.0f, 0.0f); + _hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + _hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + } } void Head::reset() { _yaw = _pitch = _roll = 0.0f; _leanForward = _leanSideways = 0.0f; + + for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { + _hairTuft[t].basePosition = _position + _orientation.getUp() * _scale * 0.9f; + _hairTuft[t].midPosition = _hairTuft[t].basePosition + _orientation.getUp() * _hairTuft[t].length * ONE_HALF; + _hairTuft[t].endPosition = _hairTuft[t].midPosition + _orientation.getUp() * _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); + } } - void Head::simulate(float deltaTime, bool isMine) { const float HEAD_MOTION_DECAY = 0.00; @@ -109,7 +133,9 @@ void Head::simulate(float deltaTime, bool isMine) { _browAudioLift *= 0.7f; // based on the nature of the lookat position, determine if the eyes can look / are looking at it. - determineIfLookingAtSomething(); + determineIfLookingAtSomething(); + + updateHair(deltaTime); } void Head::determineIfLookingAtSomething() { @@ -168,7 +194,7 @@ void Head::calculateGeometry(bool lookingInMirror) { } -void Head::render(bool lookingInMirror) { +void Head::render(bool lookingInMirror, glm::vec3 cameraPosition) { calculateGeometry(lookingInMirror); @@ -180,6 +206,7 @@ void Head::render(bool lookingInMirror) { renderEars(); renderMouth(); renderEyeBrows(); + renderHair(cameraPosition); if (_renderLookatVectors && _lookingAtSomething) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); @@ -430,4 +457,138 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi } +void Head::updateHair(float deltaTime) { + + 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 + = _orientation.getFront() * sinf(radian) + + _orientation.getUp() * cosf(radian); + + _hairTuft[t].basePosition = _position + _scale * 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 = _orientation.getUp(); + } + + if (endLength > 0.0f) { + endDirection = endAxis / endLength; + } else { + endDirection = _orientation.getUp(); + } + + // 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 = _orientation.getUp(); + } + + if (newEndLength > 0.0f) { + newEndDirection = newEndVector/newEndLength; + } else { + newEndDirection = _orientation.getUp(); + } + + _hairTuft[t].endPosition = _hairTuft[t].midPosition + newEndDirection * _hairTuft[t].length * ONE_HALF; + _hairTuft[t].midPosition = _hairTuft[t].basePosition + newMidDirection * _hairTuft[t].length * ONE_HALF; + } +} + + + +void Head::renderHair(glm::vec3 cameraPosition) { + + 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 - cameraPosition; + + 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; + + glColor3fv(HAIR_COLOR); + + glBegin(GL_TRIANGLES); + + glVertex3f(base1.x, base1.y, base1.z ); + glVertex3f(base2.x, base2.y, base2.z ); + glVertex3f(mid1.x, mid1.y, mid1.z ); + + glVertex3f(base2.x, base2.y, base2.z ); + glVertex3f(mid1.x, mid1.y, mid1.z ); + 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 ); + + glEnd(); + } +} + + + + diff --git a/interface/src/Head.h b/interface/src/Head.h index 6ea9218bbf..32f7ddab7e 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -24,13 +24,15 @@ enum eyeContactTargets MOUTH }; +const int NUM_HAIR_TUFTS = 4; + class Head : public HeadData { public: Head(); void reset(); void simulate(float deltaTime, bool isMine); - void render(bool lookingInMirror); + void render(bool lookingInMirror, glm::vec3 cameraPosition); void setScale (float scale ) { _scale = scale; } void setPosition (glm::vec3 position ) { _position = position; } @@ -56,6 +58,17 @@ 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; + }; + bool _returnHeadToCenter; float _audioLoudness; glm::vec3 _skinColor; @@ -80,6 +93,7 @@ private: glm::vec3 _bodyRotation; glm::vec3 _headRotation; bool _renderLookatVectors; + HairTuft _hairTuft[NUM_HAIR_TUFTS]; // private methods void renderHeadSphere(); @@ -90,6 +104,8 @@ private: void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition); void calculateGeometry( bool lookingInMirror); void determineIfLookingAtSomething(); + void updateHair(float deltaTime); + void renderHair(glm::vec3 cameraPosition); }; #endif From 51ddf40ffeda137605fa66d578a36215b1d9f039 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 24 May 2013 11:54:55 -0700 Subject: [PATCH 2/4] cleaned up hair code --- interface/src/Head.cpp | 15 +++++++-------- interface/src/Head.h | 6 ++++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index c29145774d..44e540db45 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -64,13 +64,16 @@ Head::Head() : _renderLookatVectors(false) { for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { - _hairTuft[t].length = HAIR_LENGTH; - _hairTuft[t].thickness = HAIR_THICKNESS; + _hairTuft[t].length = HAIR_LENGTH; + _hairTuft[t].thickness = HAIR_THICKNESS; + _hairTuft[t].basePosition = glm::vec3(0.0f, 0.0f, 0.0f); + //_hairTuft[t].baseDirection = glm::vec3(0.0f, 1.0f, 0.0f); + _hairTuft[t].basePosition = glm::vec3(0.0f, 0.0f, 0.0f); _hairTuft[t].midPosition = glm::vec3(0.0f, 0.0f, 0.0f); _hairTuft[t].endPosition = glm::vec3(0.0f, 0.0f, 0.0f); _hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); - _hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + _hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); } } @@ -79,6 +82,7 @@ void Head::reset() { _leanForward = _leanSideways = 0.0f; for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { + _hairTuft[t].basePosition = _position + _orientation.getUp() * _scale * 0.9f; _hairTuft[t].midPosition = _hairTuft[t].basePosition + _orientation.getUp() * _hairTuft[t].length * ONE_HALF; _hairTuft[t].endPosition = _hairTuft[t].midPosition + _orientation.getUp() * _hairTuft[t].length * ONE_HALF; @@ -564,7 +568,6 @@ void Head::renderHair(glm::vec3 cameraPosition) { 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; @@ -588,7 +591,3 @@ void Head::renderHair(glm::vec3 cameraPosition) { } } - - - - diff --git a/interface/src/Head.h b/interface/src/Head.h index 32f7ddab7e..cdb0ea7cb4 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -24,7 +24,8 @@ enum eyeContactTargets MOUTH }; -const int NUM_HAIR_TUFTS = 4; +const int NUM_HAIR_TUFTS = 4; +const int NUM_HAIR_SEGMENTS = 4; class Head : public HeadData { public: @@ -62,11 +63,12 @@ private: { float length; float thickness; + glm::vec3 basePosition; glm::vec3 midPosition; glm::vec3 endPosition; glm::vec3 midVelocity; - glm::vec3 endVelocity; + glm::vec3 endVelocity; }; bool _returnHeadToCenter; From 56438435c165b7f618f800c4a5e068892aff45da Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 24 May 2013 17:12:14 -0700 Subject: [PATCH 3/4] made mouth conform to the head sphere --- interface/src/Head.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index b2818b857c..9306ae8769 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -78,7 +78,6 @@ Head::Head(Avatar* owningAvatar) : _hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); _hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); } - } void Head::reset() { @@ -312,6 +311,15 @@ void Head::renderMouth() { glm::vec3 rightTop = _mouthPosition + r * 0.4f + u * 0.7f + f; glm::vec3 leftBottom = _mouthPosition - r * 0.4f - u * 1.0f + f * 0.7f; glm::vec3 rightBottom = _mouthPosition + r * 0.4f - u * 1.0f + f * 0.7f; + + // constrain all mouth vertices to a sphere slightly larger than the head... + float constrainedRadius = _scale + 0.001f; + leftCorner = _position + glm::normalize(leftCorner - _position) * constrainedRadius; + rightCorner = _position + glm::normalize(rightCorner - _position) * constrainedRadius; + leftTop = _position + glm::normalize(leftTop - _position) * constrainedRadius; + rightTop = _position + glm::normalize(rightTop - _position) * constrainedRadius; + leftBottom = _position + glm::normalize(leftBottom - _position) * constrainedRadius; + rightBottom = _position + glm::normalize(rightBottom - _position) * constrainedRadius; glColor3f(0.2f, 0.0f, 0.0f); From 0c2c90b84da919e1ef53ceae8d7663be14483e0e Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 24 May 2013 18:01:25 -0700 Subject: [PATCH 4/4] cleanup --- interface/src/Head.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 0e6bf28a9e..28b526894b 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -28,8 +28,8 @@ const float HAIR_SPRING_FORCE = 10.0f; const float HAIR_TORQUE_FORCE = 0.1f; const float HAIR_GRAVITY_FORCE = 0.05f; const float HAIR_DRAG = 10.0f; -const float HAIR_LENGTH = 0.06f; -const float HAIR_THICKNESS = 0.02f; +const float HAIR_LENGTH = 0.09f; +const float HAIR_THICKNESS = 0.03f; const float IRIS_RADIUS = 0.007; const float IRIS_PROTRUSION = 0.0145f; const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png"; @@ -65,12 +65,11 @@ Head::Head(Avatar* owningAvatar) : _mohawkTriangleFan(NULL), _mohawkColors(NULL), _renderLookatVectors(false) { - + for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { _hairTuft[t].length = HAIR_LENGTH; _hairTuft[t].thickness = HAIR_THICKNESS; _hairTuft[t].basePosition = glm::vec3(0.0f, 0.0f, 0.0f); - //_hairTuft[t].baseDirection = glm::vec3(0.0f, 1.0f, 0.0f); _hairTuft[t].basePosition = glm::vec3(0.0f, 0.0f, 0.0f); _hairTuft[t].midPosition = glm::vec3(0.0f, 0.0f, 0.0f); @@ -240,6 +239,7 @@ void Head::createMohawk() { _mohawkTriangleFan[0] = glm::vec3(0, 0, 0); glm::vec3 basicColor(randFloat(), randFloat(), randFloat()); _mohawkColors[0] = basicColor; + for (int i = 1; i < MOHAWK_TRIANGLES; i++) { _mohawkTriangleFan[i] = glm::vec3((randFloat() - 0.5f) * variance, height * cosf(i * RAD_PER_TRIANGLE - PI / 2.f)