added avatar hair

This commit is contained in:
Jeffrey Ventrella 2013-05-23 22:52:43 -07:00
parent c58c0c3295
commit b74ceae61a
5 changed files with 192 additions and 11 deletions

View file

@ -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());
}

View file

@ -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

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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