Merge branch 'master' of https://github.com/worklist/hifi into particle_details

This commit is contained in:
ZappoMan 2013-12-11 10:43:33 -08:00
commit dd85f145d2
21 changed files with 155 additions and 1503 deletions

View file

@ -79,8 +79,10 @@ const int MIRROR_VIEW_TOP_PADDING = 5;
const int MIRROR_VIEW_LEFT_PADDING = 10;
const int MIRROR_VIEW_WIDTH = 265;
const int MIRROR_VIEW_HEIGHT = 215;
const float MAX_ZOOM_DISTANCE = 0.3f;
const float MIN_ZOOM_DISTANCE = 2.0f;
const float MIRROR_FULLSCREEN_DISTANCE = 0.2f;
const float MIRROR_REARVIEW_DISTANCE = 0.3f;
const float MIRROR_REARVIEW_BODY_DISTANCE = 1.f;
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message) {
fprintf(stdout, "%s", message.toLocal8Bit().constData());
@ -236,6 +238,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
}
Application::~Application() {
// make sure we don't call the idle timer any more
delete idleTimer;
// ask the audio thread to quit and wait until it is done
_audio.thread()->quit();
_audio.thread()->wait();
@ -374,13 +379,15 @@ void Application::paintGL() {
_myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation());
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
_myCamera.setTightness (0.0f); // Camera is directly connected to head without smoothing
_myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition());
_myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation());
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
_myCamera.setTightness(0.0f);
_myCamera.setDistance(MAX_ZOOM_DISTANCE);
_myCamera.setTargetPosition(_myAvatar.getHead().calculateAverageEyePosition());
float headHeight = _myAvatar.getHead().calculateAverageEyePosition().y - _myAvatar.getPosition().y;
_myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar.getScale());
_myCamera.setTargetPosition(_myAvatar.getPosition() + glm::vec3(0, headHeight, 0));
_myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
}
@ -435,10 +442,10 @@ void Application::paintGL() {
bool eyeRelativeCamera = false;
if (_rearMirrorTools->getZoomLevel() == BODY) {
_mirrorCamera.setDistance(MIN_ZOOM_DISTANCE);
_mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar.getScale());
_mirrorCamera.setTargetPosition(_myAvatar.getChestJointPosition());
} else { // HEAD zoom level
_mirrorCamera.setDistance(MAX_ZOOM_DISTANCE);
_mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar.getScale());
if (_myAvatar.getSkeletonModel().isActive() && _myAvatar.getHead().getFaceModel().isActive()) {
// as a hack until we have a better way of dealing with coordinate precision issues, reposition the
// face/body so that the average eye position lies at the origin
@ -1420,12 +1427,16 @@ void Application::processAvatarURLsMessage(unsigned char* packetData, size_t dat
if (!avatar) {
return;
}
QDataStream in(QByteArray((char*)packetData, dataBytes));
QUrl voxelURL;
in >> voxelURL;
// PER Note: message is no longer processed but used to trigger
// Dataserver lookup - redesign this to instantly ask the
// dataserver on first receipt of other avatar UUID, and also
// don't ask over and over again. Instead use this message to
// Tell the other avatars that your dataserver data has
// changed.
// invoke the set URL functions on the simulate/render thread
QMetaObject::invokeMethod(avatar->getVoxels(), "setVoxelURL", Q_ARG(QUrl, voxelURL));
//QDataStream in(QByteArray((char*)packetData, dataBytes));
//QUrl voxelURL;
//in >> voxelURL;
// use this timing to as the data-server for an updated mesh for this avatar (if we have UUID)
DataServerClient::getValuesForKeysAndUUID(QStringList() << DataServerKey::FaceMeshURL << DataServerKey::SkeletonURL,
@ -1838,9 +1849,6 @@ void Application::init() {
_particles.init();
_particles.setViewFrustum(getViewFrustum());
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL());
_palette.init(_glWidget->width(), _glWidget->height());
_palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelAddMode), 0, 0);
_palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelDeleteMode), 0, 1);
@ -2376,20 +2384,6 @@ void Application::updateTransmitter(float deltaTime) {
if (_voxels.findRayIntersection(_transmitterPickStart, direction, detail, distance, face)) {
minDistance = min(minDistance, distance);
}
NodeList* nodeList = NodeList::getInstance();
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->lock();
if (node->getLinkedData() != NULL) {
Avatar *avatar = (Avatar*)node->getLinkedData();
if (!avatar->isInitialized()) {
avatar->init();
}
if (avatar->findRayIntersection(_transmitterPickStart, direction, distance)) {
minDistance = min(minDistance, distance);
}
}
node->unlock();
}
_transmitterPickEnd = _transmitterPickStart + direction * minDistance;
} else {
@ -2621,12 +2615,11 @@ void Application::updateAvatar(float deltaTime) {
controlledBroadcastToNodes(broadcastString, endOfBroadcastStringWrite - broadcastString,
nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
// once in a while, send my urls
const float AVATAR_URLS_SEND_INTERVAL = 1.0f; // seconds
const float AVATAR_URLS_SEND_INTERVAL = 1.0f;
if (shouldDo(AVATAR_URLS_SEND_INTERVAL, deltaTime)) {
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL());
QUrl empty;
Avatar::sendAvatarURLsMessage(empty);
}
// Update _viewFrustum with latest camera and view frustum data...
// NOTE: we get this from the view frustum, to make it simpler, since the
// loadViewFrumstum() method will get the correct details from the camera
@ -3059,6 +3052,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
// render particles...
_particles.render();
// render the ambient occlusion effect if enabled
if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... AmbientOcclusion...");
_ambientOcclusionEffect.render();
}
// restore default, white specular
glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE_SPECULAR_COLOR);
@ -3142,13 +3142,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
renderWorldBox();
}
// render the ambient occlusion effect if enabled
if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... AmbientOcclusion...");
_ambientOcclusionEffect.render();
}
// brad's frustum for debugging
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum) && whichCamera.getMode() != CAMERA_MODE_MIRROR) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),

View file

@ -317,15 +317,8 @@ Menu::Menu() :
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true);
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AvatarAsBalls);
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollisionProxies);
addActionToQMenuAndActionHash(avatarOptionsMenu,
MenuOption::VoxelMode,
0,
appInstance->getAvatar()->getVoxels(),
SLOT(cycleMode()));
addActionToQMenuAndActionHash(avatarOptionsMenu,
MenuOption::FaceMode,
0,
@ -782,10 +775,6 @@ void Menu::editPreferences() {
QFormLayout* form = new QFormLayout();
layout->addLayout(form, 1);
QLineEdit* avatarURL = new QLineEdit(applicationInstance->getAvatar()->getVoxels()->getVoxelURL().toString());
avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
form->addRow("Avatar URL:", avatarURL);
QString faceURLString = applicationInstance->getProfile()->getFaceModelURL().toString();
QLineEdit* faceURLEdit = new QLineEdit(faceURLString);
faceURLEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
@ -869,11 +858,6 @@ void Menu::editPreferences() {
skeletonModelURL.toString().toLocal8Bit().constData());
}
QUrl avatarVoxelURL(avatarURL->text());
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
Avatar::sendAvatarURLsMessage(avatarVoxelURL);
applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum());
_maxVoxels = maxVoxels->value();

View file

@ -147,7 +147,6 @@ namespace MenuOption {
const QString AboutApp = "About Interface";
const QString AmbientOcclusion = "Ambient Occlusion";
const QString Avatars = "Avatars";
const QString AvatarAsBalls = "Avatar as Balls";
const QString Atmosphere = "Atmosphere";
const QString AutomaticallyAuditTree = "Automatically Audit Tree Stats";
const QString Bandwidth = "Bandwidth Display";

View file

@ -519,33 +519,6 @@ void renderNudgeGuide(float voxelX, float voxelY, float voxelZ, float voxelS) {
glEnd();
}
void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness) {
glColor4f(0.0f, 0.0f, 0.0f, darkness);
int num = 20;
float y = 0.001f;
float x2 = 0.0f;
float z2 = radius;
float x1;
float z1;
glBegin(GL_TRIANGLES);
for (int i=1; i<num+1; i++) {
x1 = x2;
z1 = z2;
float r = ((float)i / (float)num) * PIf * 2.0;
x2 = radius * sin(r);
z2 = radius * cos(r);
glVertex3f(position.x, y, position.z );
glVertex3f(position.x + x1, y, position.z + z1);
glVertex3f(position.x + x2, y, position.z + z2);
}
glEnd();
}

View file

@ -77,8 +77,6 @@ void renderNudgeGuide(float voxelX, float voxelY, float voxelZ, float voxelS);
void renderCollisionOverlay(int width, int height, float magnitude);
void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness);
void renderOrientationDirections( glm::vec3 position, const glm::quat& orientation, float size );
void renderSphereOutline(glm::vec3 position, float radius, int numSides, glm::vec3 cameraPosition);

View file

@ -48,7 +48,6 @@ const float HEAD_MAX_PITCH = 45;
const float HEAD_MIN_PITCH = -45;
const float HEAD_MAX_YAW = 85;
const float HEAD_MIN_YAW = -85;
const float PERIPERSONAL_RADIUS = 1.0f;
const float AVATAR_BRAKING_STRENGTH = 40.0f;
const float MOUSE_RAY_TOUCH_RANGE = 0.01f;
const float FLOATING_HEIGHT = 0.13f;
@ -61,7 +60,7 @@ const float SKIN_COLOR[] = {1.0, 0.84, 0.66};
const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63};
const int NUM_BODY_CONE_SIDES = 9;
const float chatMessageScale = 0.0015;
const float chatMessageHeight = 0.20;
const float chatMessageHeight = 0.4f;
void Avatar::sendAvatarURLsMessage(const QUrl& voxelURL) {
QByteArray message;
@ -97,7 +96,6 @@ Avatar::Avatar(Node* owningNode) :
_mouseRayDirection(0.0f, 0.0f, 0.0f),
_isCollisionsOn(true),
_leadingAvatar(NULL),
_voxels(this),
_moving(false),
_initialized(false),
_handHoldingPosition(0.0f, 0.0f, 0.0f),
@ -113,17 +111,13 @@ Avatar::Avatar(Node* owningNode) :
_skeleton.initialize();
initializeBodyBalls();
_height = _skeleton.getHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius + _bodyBall[BODY_BALL_HEAD_BASE].radius;
_height = _skeleton.getHeight();
_maxArmLength = _skeleton.getArmLength();
_pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius;
_pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius;
_pelvisStandingHeight = _skeleton.getPelvisStandingHeight();
_pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight();
_pelvisToHeadLength = _skeleton.getPelvisToHeadLength();
_avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS);
if (BALLS_ON) {
_balls = new Balls(100);
} else {
@ -132,126 +126,6 @@ Avatar::Avatar(Node* owningNode) :
}
void Avatar::initializeBodyBalls() {
_ballSpringsInitialized = false; //this gets set to true on the first update pass...
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
_bodyBall[b].parentJoint = AVATAR_JOINT_NULL;
_bodyBall[b].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[b].position = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[b].velocity = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[b].radius = 0.0;
_bodyBall[b].touchForce = 0.0;
_bodyBall[b].isCollidable = true;
_bodyBall[b].jointTightness = BODY_SPRING_DEFAULT_TIGHTNESS;
}
// specify the radius of each ball
_bodyBall[BODY_BALL_PELVIS].radius = BODY_BALL_RADIUS_PELVIS;
_bodyBall[BODY_BALL_TORSO].radius = BODY_BALL_RADIUS_TORSO;
_bodyBall[BODY_BALL_CHEST].radius = BODY_BALL_RADIUS_CHEST;
_bodyBall[BODY_BALL_NECK_BASE].radius = BODY_BALL_RADIUS_NECK_BASE;
_bodyBall[BODY_BALL_HEAD_BASE].radius = BODY_BALL_RADIUS_HEAD_BASE;
_bodyBall[BODY_BALL_LEFT_COLLAR].radius = BODY_BALL_RADIUS_LEFT_COLLAR;
_bodyBall[BODY_BALL_LEFT_SHOULDER].radius = BODY_BALL_RADIUS_LEFT_SHOULDER;
_bodyBall[BODY_BALL_LEFT_ELBOW].radius = BODY_BALL_RADIUS_LEFT_ELBOW;
_bodyBall[BODY_BALL_LEFT_WRIST].radius = BODY_BALL_RADIUS_LEFT_WRIST;
_bodyBall[BODY_BALL_LEFT_FINGERTIPS].radius = BODY_BALL_RADIUS_LEFT_FINGERTIPS;
_bodyBall[BODY_BALL_RIGHT_COLLAR].radius = BODY_BALL_RADIUS_RIGHT_COLLAR;
_bodyBall[BODY_BALL_RIGHT_SHOULDER].radius = BODY_BALL_RADIUS_RIGHT_SHOULDER;
_bodyBall[BODY_BALL_RIGHT_ELBOW].radius = BODY_BALL_RADIUS_RIGHT_ELBOW;
_bodyBall[BODY_BALL_RIGHT_WRIST].radius = BODY_BALL_RADIUS_RIGHT_WRIST;
_bodyBall[BODY_BALL_RIGHT_FINGERTIPS].radius = BODY_BALL_RADIUS_RIGHT_FINGERTIPS;
_bodyBall[BODY_BALL_LEFT_HIP].radius = BODY_BALL_RADIUS_LEFT_HIP;
_bodyBall[BODY_BALL_LEFT_KNEE].radius = BODY_BALL_RADIUS_LEFT_KNEE;
_bodyBall[BODY_BALL_LEFT_HEEL].radius = BODY_BALL_RADIUS_LEFT_HEEL;
_bodyBall[BODY_BALL_LEFT_TOES].radius = BODY_BALL_RADIUS_LEFT_TOES;
_bodyBall[BODY_BALL_RIGHT_HIP].radius = BODY_BALL_RADIUS_RIGHT_HIP;
_bodyBall[BODY_BALL_RIGHT_KNEE].radius = BODY_BALL_RADIUS_RIGHT_KNEE;
_bodyBall[BODY_BALL_RIGHT_HEEL].radius = BODY_BALL_RADIUS_RIGHT_HEEL;
_bodyBall[BODY_BALL_RIGHT_TOES].radius = BODY_BALL_RADIUS_RIGHT_TOES;
// specify the parent joint for each ball
_bodyBall[BODY_BALL_PELVIS].parentJoint = AVATAR_JOINT_PELVIS;
_bodyBall[BODY_BALL_TORSO].parentJoint = AVATAR_JOINT_TORSO;
_bodyBall[BODY_BALL_CHEST].parentJoint = AVATAR_JOINT_CHEST;
_bodyBall[BODY_BALL_NECK_BASE].parentJoint = AVATAR_JOINT_NECK_BASE;
_bodyBall[BODY_BALL_HEAD_BASE].parentJoint = AVATAR_JOINT_HEAD_BASE;
_bodyBall[BODY_BALL_HEAD_TOP].parentJoint = AVATAR_JOINT_HEAD_TOP;
_bodyBall[BODY_BALL_LEFT_COLLAR].parentJoint = AVATAR_JOINT_LEFT_COLLAR;
_bodyBall[BODY_BALL_LEFT_SHOULDER].parentJoint = AVATAR_JOINT_LEFT_SHOULDER;
_bodyBall[BODY_BALL_LEFT_ELBOW].parentJoint = AVATAR_JOINT_LEFT_ELBOW;
_bodyBall[BODY_BALL_LEFT_WRIST].parentJoint = AVATAR_JOINT_LEFT_WRIST;
_bodyBall[BODY_BALL_LEFT_FINGERTIPS].parentJoint = AVATAR_JOINT_LEFT_FINGERTIPS;
_bodyBall[BODY_BALL_RIGHT_COLLAR].parentJoint = AVATAR_JOINT_RIGHT_COLLAR;
_bodyBall[BODY_BALL_RIGHT_SHOULDER].parentJoint = AVATAR_JOINT_RIGHT_SHOULDER;
_bodyBall[BODY_BALL_RIGHT_ELBOW].parentJoint = AVATAR_JOINT_RIGHT_ELBOW;
_bodyBall[BODY_BALL_RIGHT_WRIST].parentJoint = AVATAR_JOINT_RIGHT_WRIST;
_bodyBall[BODY_BALL_RIGHT_FINGERTIPS].parentJoint = AVATAR_JOINT_RIGHT_FINGERTIPS;
_bodyBall[BODY_BALL_LEFT_HIP].parentJoint = AVATAR_JOINT_LEFT_HIP;
_bodyBall[BODY_BALL_LEFT_KNEE].parentJoint = AVATAR_JOINT_LEFT_KNEE;
_bodyBall[BODY_BALL_LEFT_HEEL].parentJoint = AVATAR_JOINT_LEFT_HEEL;
_bodyBall[BODY_BALL_LEFT_TOES].parentJoint = AVATAR_JOINT_LEFT_TOES;
_bodyBall[BODY_BALL_RIGHT_HIP].parentJoint = AVATAR_JOINT_RIGHT_HIP;
_bodyBall[BODY_BALL_RIGHT_KNEE].parentJoint = AVATAR_JOINT_RIGHT_KNEE;
_bodyBall[BODY_BALL_RIGHT_HEEL].parentJoint = AVATAR_JOINT_RIGHT_HEEL;
_bodyBall[BODY_BALL_RIGHT_TOES].parentJoint = AVATAR_JOINT_RIGHT_TOES;
// specify the parent offset for each ball
_bodyBall[BODY_BALL_PELVIS].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_TORSO].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_CHEST].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_NECK_BASE].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_HEAD_BASE].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_HEAD_TOP].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_COLLAR].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_SHOULDER].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_ELBOW].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_WRIST].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_FINGERTIPS].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_COLLAR].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_SHOULDER].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_ELBOW].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_WRIST].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_FINGERTIPS].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_HIP].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_KNEE].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_HEEL].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_LEFT_TOES].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_HIP].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_KNEE].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_HEEL].parentOffset = glm::vec3(0.0, 0.0, 0.0);
_bodyBall[BODY_BALL_RIGHT_TOES].parentOffset = glm::vec3(0.0, 0.0, 0.0);
// specify the parent BALL for each ball
_bodyBall[BODY_BALL_PELVIS].parentBall = BODY_BALL_NULL;
_bodyBall[BODY_BALL_TORSO].parentBall = BODY_BALL_PELVIS;
_bodyBall[BODY_BALL_CHEST].parentBall = BODY_BALL_TORSO;
_bodyBall[BODY_BALL_NECK_BASE].parentBall = BODY_BALL_CHEST;
_bodyBall[BODY_BALL_HEAD_BASE].parentBall = BODY_BALL_NECK_BASE;
_bodyBall[BODY_BALL_HEAD_TOP].parentBall = BODY_BALL_HEAD_BASE;
_bodyBall[BODY_BALL_LEFT_COLLAR].parentBall = BODY_BALL_CHEST;
_bodyBall[BODY_BALL_LEFT_SHOULDER].parentBall = BODY_BALL_LEFT_COLLAR;
_bodyBall[BODY_BALL_LEFT_ELBOW].parentBall = BODY_BALL_LEFT_SHOULDER;
_bodyBall[BODY_BALL_LEFT_WRIST].parentBall = BODY_BALL_LEFT_ELBOW;
_bodyBall[BODY_BALL_LEFT_FINGERTIPS].parentBall = BODY_BALL_LEFT_WRIST;
_bodyBall[BODY_BALL_RIGHT_COLLAR].parentBall = BODY_BALL_CHEST;
_bodyBall[BODY_BALL_RIGHT_SHOULDER].parentBall = BODY_BALL_RIGHT_COLLAR;
_bodyBall[BODY_BALL_RIGHT_ELBOW].parentBall = BODY_BALL_RIGHT_SHOULDER;
_bodyBall[BODY_BALL_RIGHT_WRIST].parentBall = BODY_BALL_RIGHT_ELBOW;
_bodyBall[BODY_BALL_RIGHT_FINGERTIPS].parentBall = BODY_BALL_RIGHT_WRIST;
_bodyBall[BODY_BALL_LEFT_HIP].parentBall = BODY_BALL_PELVIS;
_bodyBall[BODY_BALL_LEFT_KNEE].parentBall = BODY_BALL_LEFT_HIP;
_bodyBall[BODY_BALL_LEFT_HEEL].parentBall = BODY_BALL_LEFT_KNEE;
_bodyBall[BODY_BALL_LEFT_TOES].parentBall = BODY_BALL_LEFT_HEEL;
_bodyBall[BODY_BALL_RIGHT_HIP].parentBall = BODY_BALL_PELVIS;
_bodyBall[BODY_BALL_RIGHT_KNEE].parentBall = BODY_BALL_RIGHT_HIP;
_bodyBall[BODY_BALL_RIGHT_HEEL].parentBall = BODY_BALL_RIGHT_KNEE;
_bodyBall[BODY_BALL_RIGHT_TOES].parentBall = BODY_BALL_RIGHT_HEEL;
}
Avatar::~Avatar() {
_headData = NULL;
_handData = NULL;
@ -267,7 +141,6 @@ void Avatar::init() {
_head.init();
_hand.init();
_skeletonModel.init();
_voxels.init();
_initialized = true;
}
@ -296,10 +169,6 @@ void Avatar::follow(Avatar* leadingAvatar) {
void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
glm::quat orientation = getOrientation();
glm::vec3 front = orientation * IDENTITY_FRONT;
glm::vec3 right = orientation * IDENTITY_RIGHT;
if (_leadingAvatar && !_leadingAvatar->getOwningNode()->isAlive()) {
follow(NULL);
}
@ -339,67 +208,18 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
// update avatar skeleton
_skeleton.update(deltaTime, getOrientation(), _position);
//determine the lengths of the body springs now that we have updated the skeleton at least once
if (!_ballSpringsInitialized) {
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
glm::vec3 targetPosition
= _skeleton.joint[_bodyBall[b].parentJoint].position
+ _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset;
glm::vec3 parentTargetPosition
= _skeleton.joint[_bodyBall[b].parentJoint].position
+ _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset;
_bodyBall[b].springLength = glm::length(targetPosition - parentTargetPosition);
}
_ballSpringsInitialized = true;
}
// if this is not my avatar, then hand position comes from transmitted data
_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handPosition;
//update the movement of the hand and process handshaking with other avatars...
updateHandMovementAndTouching(deltaTime, enableHandMovement);
_avatarTouch.simulate(deltaTime);
// update body balls
updateBodyBalls(deltaTime);
//apply the head lean values to the ball positions...
if (USING_HEAD_LEAN) {
if (fabs(_head.getLeanSideways() + _head.getLeanForward()) > 0.0f) {
glm::vec3 headLean =
right * _head.getLeanSideways() +
front * _head.getLeanForward();
_bodyBall[BODY_BALL_TORSO].position += headLean * 0.1f;
_bodyBall[BODY_BALL_CHEST].position += headLean * 0.4f;
_bodyBall[BODY_BALL_NECK_BASE].position += headLean * 0.7f;
_bodyBall[BODY_BALL_HEAD_BASE].position += headLean * 1.0f;
_bodyBall[BODY_BALL_LEFT_COLLAR].position += headLean * 0.6f;
_bodyBall[BODY_BALL_LEFT_SHOULDER].position += headLean * 0.6f;
_bodyBall[BODY_BALL_LEFT_ELBOW].position += headLean * 0.2f;
_bodyBall[BODY_BALL_LEFT_WRIST].position += headLean * 0.1f;
_bodyBall[BODY_BALL_LEFT_FINGERTIPS].position += headLean * 0.0f;
_bodyBall[BODY_BALL_RIGHT_COLLAR].position += headLean * 0.6f;
_bodyBall[BODY_BALL_RIGHT_SHOULDER].position += headLean * 0.6f;
_bodyBall[BODY_BALL_RIGHT_ELBOW].position += headLean * 0.2f;
_bodyBall[BODY_BALL_RIGHT_WRIST].position += headLean * 0.1f;
_bodyBall[BODY_BALL_RIGHT_FINGERTIPS].position += headLean * 0.0f;
}
}
_hand.simulate(deltaTime, false);
_skeletonModel.simulate(deltaTime);
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
glm::vec3 headPosition;
if (Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls) || !_skeletonModel.getHeadPosition(headPosition)) {
headPosition = _bodyBall[BODY_BALL_HEAD_BASE].position;
}
_skeletonModel.getHeadPosition(headPosition);
_head.setPosition(headPosition);
_head.setScale(_scale);
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
@ -444,9 +264,6 @@ static TextRenderer* textRenderer() {
void Avatar::render(bool forceRenderHead) {
// render a simple round on the ground projected down from the avatar's position
renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f), _scale * 0.1f, 0.2f);
{
// glow when moving in the distance
glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition();
@ -486,7 +303,7 @@ void Avatar::render(bool forceRenderHead) {
}
glPushMatrix();
glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight * _scale;
glm::vec3 chatPosition = getPosition() + getBodyUpDirection() * chatMessageHeight * _scale;
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
glm::vec3 chatAxis = glm::axis(chatRotation);
@ -521,90 +338,7 @@ void Avatar::render(bool forceRenderHead) {
}
}
void Avatar::resetBodyBalls() {
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
glm::vec3 targetPosition
= _skeleton.joint[_bodyBall[b].parentJoint].position
+ _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset;
_bodyBall[b].position = targetPosition; // put ball on target position
_bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f);
}
}
void Avatar::updateBodyBalls(float deltaTime) {
// Check for a large repositioning, and re-initialize balls if this has happened
const float BEYOND_BODY_SPRING_RANGE = _scale * 2.f;
if (glm::length(_position - _bodyBall[BODY_BALL_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) {
resetBodyBalls();
}
glm::quat orientation = getOrientation();
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
glm::vec3 springVector;
float length = 0.0f;
if (_ballSpringsInitialized) {
// apply spring forces
springVector = _bodyBall[b].position;
if (b == BODY_BALL_PELVIS) {
springVector -= _position;
} else {
springVector -= _bodyBall[_bodyBall[b].parentBall].position;
}
length = glm::length(springVector);
if (length > 0.0f) { // to avoid divide by zero
glm::vec3 springDirection = springVector / length;
float force = (length - _skeleton.joint[b].length) * BODY_SPRING_FORCE * deltaTime;
_bodyBall[b].velocity -= springDirection * force;
if (_bodyBall[b].parentBall != BODY_BALL_NULL) {
_bodyBall[_bodyBall[b].parentBall].velocity += springDirection * force;
}
}
}
// apply tightness force - (causing ball position to be close to skeleton joint position)
glm::vec3 targetPosition
= _skeleton.joint[_bodyBall[b].parentJoint].position
+ _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset;
_bodyBall[b].velocity += (targetPosition - _bodyBall[b].position) * _bodyBall[b].jointTightness * deltaTime;
// apply decay
float decay = 1.0 - BODY_SPRING_DECAY * deltaTime;
if (decay > 0.0) {
_bodyBall[b].velocity *= decay;
} else {
_bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f);
}
// update position by velocity...
_bodyBall[b].position += _bodyBall[b].velocity * deltaTime;
// update rotation
const float SMALL_SPRING_LENGTH = 0.001f; // too-small springs can change direction rapidly
if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < SMALL_SPRING_LENGTH) {
_bodyBall[b].rotation = orientation * _skeleton.joint[_bodyBall[b].parentJoint].absoluteBindPoseRotation;
} else {
glm::vec3 parentDirection = _bodyBall[ _bodyBall[b].parentBall ].rotation * JOINT_DIRECTION;
_bodyBall[b].rotation = rotationBetween(parentDirection, springVector) *
_bodyBall[ _bodyBall[b].parentBall ].rotation;
}
}
// copy the head's rotation
_bodyBall[BODY_BALL_HEAD_BASE].rotation = _bodyBall[BODY_BALL_HEAD_TOP].rotation = _head.getOrientation();
_bodyBall[BODY_BALL_HEAD_BASE].position = _bodyBall[BODY_BALL_NECK_BASE].position +
_bodyBall[BODY_BALL_HEAD_BASE].rotation * _skeleton.joint[BODY_BALL_HEAD_BASE].bindPosePosition;
_bodyBall[BODY_BALL_HEAD_TOP].position = _bodyBall[BODY_BALL_HEAD_BASE].position +
_bodyBall[BODY_BALL_HEAD_TOP].rotation * _skeleton.joint[BODY_BALL_HEAD_TOP].bindPosePosition;
}
// returns true if the Leap controls any of the avatar's hands.
bool Avatar::updateLeapHandPositions() {
@ -665,7 +399,7 @@ void Avatar::updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJ
float distance = glm::length(armVector);
// don't let right hand get dragged beyond maximum arm length...
float armLength = (_skeletonModel.isActive() && !Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)) ?
float armLength = _skeletonModel.isActive() ?
_skeletonModel.getRightArmLength() : _skeleton.getArmLength();
const float ARM_RETRACTION = 0.75f;
float retractedArmLength = armLength * ARM_RETRACTION;
@ -709,79 +443,19 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
return glm::angleAxis(angle * proportion, axis);
}
float Avatar::getBallRenderAlpha(int ball, bool forceRenderHead) const {
return 1.0f;
}
void Avatar::renderBody(bool forceRenderHead) {
if (_head.getVideoFace().isFullFrame()) {
// Render the full-frame video
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead);
if (alpha > 0.0f) {
_head.getVideoFace().render(1.0f);
}
} else if (Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)) {
// Render the body as balls and cones
glm::vec3 skinColor, darkSkinColor;
getSkinColors(skinColor, darkSkinColor);
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
float alpha = getBallRenderAlpha(b, forceRenderHead);
// When we have leap hands, hide part of the arms.
if (_hand.getNumPalms() > 0) {
if (b == BODY_BALL_LEFT_FINGERTIPS
|| b == BODY_BALL_RIGHT_FINGERTIPS) {
continue;
}
}
// Always render other people, and render myself when beyond threshold distance
if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special
if (alpha > 0.0f) {
_head.render(alpha, true);
}
} else if (alpha > 0.0f) {
// Render the body ball sphere
glColor3f(skinColor.r + _bodyBall[b].touchForce * 0.3f,
skinColor.g - _bodyBall[b].touchForce * 0.2f,
skinColor.b - _bodyBall[b].touchForce * 0.1f);
if ((b != BODY_BALL_HEAD_TOP )
&& (b != BODY_BALL_HEAD_BASE )) {
glPushMatrix();
glTranslatef(_bodyBall[b].position.x, _bodyBall[b].position.y, _bodyBall[b].position.z);
glutSolidSphere(_bodyBall[b].radius, 20.0f, 20.0f);
glPopMatrix();
}
// Render the cone connecting this ball to its parent
if (_bodyBall[b].parentBall != BODY_BALL_NULL) {
if ((b != BODY_BALL_HEAD_TOP)
&& (b != BODY_BALL_HEAD_BASE)
&& (b != BODY_BALL_PELVIS)
&& (b != BODY_BALL_TORSO)
&& (b != BODY_BALL_CHEST)
&& (b != BODY_BALL_LEFT_COLLAR)
&& (b != BODY_BALL_LEFT_SHOULDER)
&& (b != BODY_BALL_RIGHT_COLLAR)
&& (b != BODY_BALL_RIGHT_SHOULDER)) {
glColor3fv((const GLfloat*)&darkSkinColor);
float r2 = _bodyBall[b].radius * 0.8;
renderJointConnectingCone(_bodyBall[_bodyBall[b].parentBall].position, _bodyBall[b].position, r2, r2);
}
}
}
}
} else {
// Render the body's voxels and head
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead);
if (alpha > 0.0f) {
if (!_skeletonModel.render(alpha)) {
_voxels.render(false);
}
_head.render(alpha, false);
}
glm::vec3 pos = getPosition();
//printf("Render other at %.3f, %.2f, %.2f\n", pos.x, pos.y, pos.z);
_skeletonModel.render(1.0f);
_head.render(1.0f, false);
}
_hand.render(false);
}
@ -789,33 +463,13 @@ void Avatar::renderBody(bool forceRenderHead) {
void Avatar::getSkinColors(glm::vec3& lighter, glm::vec3& darker) {
lighter = glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]);
darker = glm::vec3(DARK_SKIN_COLOR[0], DARK_SKIN_COLOR[1], DARK_SKIN_COLOR[2]);
if (!Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls) && _head.getFaceModel().isActive()) {
if (_head.getFaceModel().isActive()) {
lighter = glm::vec3(_head.getFaceModel().computeAverageColor());
const float SKIN_DARKENING = 0.9f;
darker = lighter * SKIN_DARKENING;
}
}
void Avatar::getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const {
position = _bodyBall[jointID].position;
rotation = _bodyBall[jointID].rotation;
}
bool Avatar::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
float minDistance = FLT_MAX;
for (int i = 0; i < NUM_AVATAR_BODY_BALLS; i++) {
float distance;
if (rayIntersectsSphere(origin, direction, _bodyBall[i].position, _bodyBall[i].radius, distance)) {
minDistance = min(minDistance, distance);
}
}
if (minDistance == FLT_MAX) {
return false;
}
distance = minDistance;
return true;
}
bool Avatar::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
glm::vec3& penetration, int skeletonSkipIndex) {
bool didPenetrate = false;
@ -929,37 +583,11 @@ void Avatar::setScale(const float scale) {
_skeleton.setScale(_scale);
// specify the new radius of each ball
_bodyBall[BODY_BALL_PELVIS].radius = _scale * BODY_BALL_RADIUS_PELVIS;
_bodyBall[BODY_BALL_TORSO].radius = _scale * BODY_BALL_RADIUS_TORSO;
_bodyBall[BODY_BALL_CHEST].radius = _scale * BODY_BALL_RADIUS_CHEST;
_bodyBall[BODY_BALL_NECK_BASE].radius = _scale * BODY_BALL_RADIUS_NECK_BASE;
_bodyBall[BODY_BALL_HEAD_BASE].radius = _scale * BODY_BALL_RADIUS_HEAD_BASE;
_bodyBall[BODY_BALL_LEFT_COLLAR].radius = _scale * BODY_BALL_RADIUS_LEFT_COLLAR;
_bodyBall[BODY_BALL_LEFT_SHOULDER].radius = _scale * BODY_BALL_RADIUS_LEFT_SHOULDER;
_bodyBall[BODY_BALL_LEFT_ELBOW].radius = _scale * BODY_BALL_RADIUS_LEFT_ELBOW;
_bodyBall[BODY_BALL_LEFT_WRIST].radius = _scale * BODY_BALL_RADIUS_LEFT_WRIST;
_bodyBall[BODY_BALL_LEFT_FINGERTIPS].radius = _scale * BODY_BALL_RADIUS_LEFT_FINGERTIPS;
_bodyBall[BODY_BALL_RIGHT_COLLAR].radius = _scale * BODY_BALL_RADIUS_RIGHT_COLLAR;
_bodyBall[BODY_BALL_RIGHT_SHOULDER].radius = _scale * BODY_BALL_RADIUS_RIGHT_SHOULDER;
_bodyBall[BODY_BALL_RIGHT_ELBOW].radius = _scale * BODY_BALL_RADIUS_RIGHT_ELBOW;
_bodyBall[BODY_BALL_RIGHT_WRIST].radius = _scale * BODY_BALL_RADIUS_RIGHT_WRIST;
_bodyBall[BODY_BALL_RIGHT_FINGERTIPS].radius = _scale * BODY_BALL_RADIUS_RIGHT_FINGERTIPS;
_bodyBall[BODY_BALL_LEFT_HIP].radius = _scale * BODY_BALL_RADIUS_LEFT_HIP;
_bodyBall[BODY_BALL_LEFT_KNEE].radius = _scale * BODY_BALL_RADIUS_LEFT_KNEE;
_bodyBall[BODY_BALL_LEFT_HEEL].radius = _scale * BODY_BALL_RADIUS_LEFT_HEEL;
_bodyBall[BODY_BALL_LEFT_TOES].radius = _scale * BODY_BALL_RADIUS_LEFT_TOES;
_bodyBall[BODY_BALL_RIGHT_HIP].radius = _scale * BODY_BALL_RADIUS_RIGHT_HIP;
_bodyBall[BODY_BALL_RIGHT_KNEE].radius = _scale * BODY_BALL_RADIUS_RIGHT_KNEE;
_bodyBall[BODY_BALL_RIGHT_HEEL].radius = _scale * BODY_BALL_RADIUS_RIGHT_HEEL;
_bodyBall[BODY_BALL_RIGHT_TOES].radius = _scale * BODY_BALL_RADIUS_RIGHT_TOES;
_height = _skeleton.getHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius + _bodyBall[BODY_BALL_HEAD_BASE].radius;
_height = _skeleton.getHeight();
_maxArmLength = _skeleton.getArmLength();
_pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius;
_pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[BODY_BALL_LEFT_HEEL].radius;
_pelvisStandingHeight = _skeleton.getPelvisStandingHeight();
_pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight();
_pelvisToHeadLength = _skeleton.getPelvisToHeadLength();
_avatarTouch.setReachableRadius(_scale * PERIPERSONAL_RADIUS);
}

View file

@ -15,8 +15,6 @@
#include <AvatarData.h>
#include "AvatarTouch.h"
#include "AvatarVoxelSystem.h"
#include "Balls.h"
#include "Hand.h"
#include "Head.h"
@ -160,20 +158,9 @@ public:
Hand& getHand() { return _hand; }
glm::quat getOrientation() const;
glm::quat getWorldAlignedOrientation() const;
AvatarVoxelSystem* getVoxels() { return &_voxels; }
void getSkinColors(glm::vec3& lighter, glm::vec3& darker);
// Get the position/rotation of a single body ball
void getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const;
/// Checks for an intersection between the described ray and any of the avatar's body balls.
/// \param origin the origin of the ray
/// \param direction the unit direction vector
/// \param[out] distance the variable in which to store the distance to intersection
/// \return whether or not the ray intersected
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
/// Checks for penetration between the described sphere and the avatar.
/// \param penetratorCenter the center of the penetration test sphere
/// \param penetratorRadius the radius of the penetration test sphere
@ -218,7 +205,6 @@ protected:
SkeletonModel _skeletonModel;
bool _ballSpringsInitialized;
float _bodyYawDelta;
AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ];
AvatarMode _mode;
glm::vec3 _velocity;
glm::vec3 _thrust;
@ -229,14 +215,12 @@ protected:
float _scale;
float _height;
Balls* _balls;
AvatarTouch _avatarTouch;
glm::vec3 _worldUpDirection;
glm::vec3 _mouseRayOrigin;
glm::vec3 _mouseRayDirection;
bool _isCollisionsOn;
Avatar* _leadingAvatar;
float _stringLength;
AvatarVoxelSystem _voxels;
bool _moving; ///< set when position is changing
@ -245,7 +229,6 @@ protected:
glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; }
glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
void updateBodyBalls(float deltaTime);
bool updateLeapHandPositions();
void updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJointID);
void setScale(const float scale);

View file

@ -1,120 +0,0 @@
//
// AvatarTouch.cpp
// interface
//
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <iostream>
#include <glm/glm.hpp>
#include <SharedUtil.h>
#include "AvatarTouch.h"
#include "InterfaceConfig.h"
#include "Util.h"
const float THREAD_RADIUS = 0.007;
const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.2;
const float AVATAR_FACING_THRESHOLD = -0.5f; // (-1 to 1) (larger value indicates narrower angle of influence
AvatarTouch::AvatarTouch() {
_myHandPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_yourHandPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_myBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_yourBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_vectorBetweenHands = glm::vec3(0.0f, 0.0f, 0.0f);
_myHandState = HAND_STATE_NULL;
_yourHandState = HAND_STATE_NULL;
_reachableRadius = 0.0f;
_weAreHoldingHands = false;
_canReachToOtherAvatar = false;
_handsCloseEnoughToGrasp = false;
_hasInteractingOther = false;
for (int p=0; p<NUM_PARTICLE_POINTS; p++) {
_point[p] = glm::vec3(0.0, 0.0, 0.0);
}
}
void AvatarTouch::simulate (float deltaTime) {
_canReachToOtherAvatar = false; // default
if (_hasInteractingOther) {
glm::vec3 vectorBetweenBodies = _yourBodyPosition - _myBodyPosition;
float distanceBetweenBodies = glm::length(vectorBetweenBodies);
//KEEP THIS - it is another variation that we are considering getting rid of
//the following code take into account of the two avatars are facing each other
/*
glm::vec3 directionBetweenBodies = vectorBetweenBodies / distanceBetweenBodies;
bool facingEachOther = false;
glm::vec3 myFront = _myOrientation * AVATAR_FRONT;
glm::vec3 yourFront = _yourOrientation * AVATAR_FRONT;
if (( glm::dot(myFront, yourFront ) < -AVATAR_FACING_THRESHOLD) // we're facing each other
&& ( glm::dot(myFront, directionBetweenBodies ) > AVATAR_FACING_THRESHOLD)) { // I'm facing you
facingEachOther = true;
}
*/
if (distanceBetweenBodies < _reachableRadius)
{
_canReachToOtherAvatar = true;
_vectorBetweenHands = _yourHandPosition - _myHandPosition;
float distanceBetweenHands = glm::length(_vectorBetweenHands);
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) {
_handsCloseEnoughToGrasp = true;
} else {
_handsCloseEnoughToGrasp = false;
}
}
}
}
void AvatarTouch::render(glm::vec3 cameraPosition) {
if (_canReachToOtherAvatar) {
//show circle indicating that we can reach out to each other...
glColor4f(0.3, 0.4, 0.5, 0.5);
glm::vec3 p(_yourBodyPosition);
p.y = 0.0005f;
renderCircle(p, _reachableRadius, glm::vec3(0.0f, 1.0f, 0.0f), 30);
}
}
void AvatarTouch::renderBeamBetweenHands() {
glm::vec3 v1(_myHandPosition);
glm::vec3 v2(_yourHandPosition);
glLineWidth(3.0);
glColor4f(0.9f, 0.9f, 0.1f, 0.6);
glBegin(GL_LINE_STRIP);
glVertex3f(v1.x, v1.y, v1.z);
glVertex3f(v2.x, v2.y, v2.z);
glEnd();
glColor3f(0.5f, 0.3f, 0.0f);
for (int p=0; p<NUM_PARTICLE_POINTS; p++) {
_point[p] = _myHandPosition + _vectorBetweenHands * ((float)p / (float)NUM_PARTICLE_POINTS);
_point[p].x += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
_point[p].y += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
_point[p].z += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
glBegin(GL_POINTS);
glVertex3f(_point[p].x, _point[p].y, _point[p].z);
glEnd();
}
}

View file

@ -1,72 +0,0 @@
//
// AvatarTouch.h
// interface
//
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__AvatarTouch__
#define __interface__AvatarTouch__
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <AvatarData.h>
enum AvatarHandState
{
HAND_STATE_NULL = 0,
HAND_STATE_OPEN,
HAND_STATE_GRASPING,
HAND_STATE_POINTING,
NUM_HAND_STATES
};
class AvatarTouch {
public:
AvatarTouch();
void simulate(float deltaTime);
void render(glm::vec3 cameraPosition);
void setHasInteractingOther(bool hasInteractingOther) { _hasInteractingOther = hasInteractingOther;}
void setMyHandPosition (glm::vec3 position ) { _myHandPosition = position;}
void setYourHandPosition (glm::vec3 position ) { _yourHandPosition = position;}
void setMyOrientation (glm::quat orientation ) { _myOrientation = orientation;}
void setYourOrientation (glm::quat orientation ) { _yourOrientation = orientation;}
void setMyBodyPosition (glm::vec3 position ) { _myBodyPosition = position;}
void setYourBodyPosition (glm::vec3 position ) { _yourBodyPosition = position;}
void setMyHandState (int state ) { _myHandState = state;}
void setYourHandState (int state ) { _yourHandState = state;}
void setReachableRadius (float radius ) { _reachableRadius = radius;}
void setHoldingHands (bool holding ) { _weAreHoldingHands = holding;}
bool getAbleToReachOtherAvatar () const {return _canReachToOtherAvatar; }
bool getHandsCloseEnoughToGrasp() const {return _handsCloseEnoughToGrasp;}
bool getHoldingHands () const {return _weAreHoldingHands; }
private:
static const int NUM_PARTICLE_POINTS = 100;
bool _hasInteractingOther;
bool _weAreHoldingHands;
glm::vec3 _point [NUM_PARTICLE_POINTS];
glm::vec3 _myBodyPosition;
glm::vec3 _yourBodyPosition;
glm::vec3 _myHandPosition;
glm::vec3 _yourHandPosition;
glm::quat _myOrientation;
glm::quat _yourOrientation;
glm::vec3 _vectorBetweenHands;
int _myHandState;
int _yourHandState;
bool _canReachToOtherAvatar;
bool _handsCloseEnoughToGrasp;
float _reachableRadius;
void renderBeamBetweenHands();
};
#endif

View file

@ -1,339 +0,0 @@
//
// AvatarVoxelSystem.cpp
// interface
//
// Created by Andrzej Kapolka on 5/31/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <cstring>
#include <QNetworkReply>
#include <GeometryUtil.h>
#include "Application.h"
#include "Avatar.h"
#include "AvatarVoxelSystem.h"
#include "renderer/ProgramObject.h"
const float AVATAR_TREE_SCALE = 1.0f;
const int MAX_VOXELS_PER_AVATAR = 10000;
const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL;
AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) :
VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR),
_initialized(false),
_mode(0),
_avatar(avatar),
_voxelReply(0) {
// we may have been created in the network thread, but we live in the main thread
moveToThread(Application::getInstance()->thread());
}
AvatarVoxelSystem::~AvatarVoxelSystem() {
if (_initialized) {
delete[] _readBoneIndicesArray;
delete[] _readBoneWeightsArray;
delete[] _writeBoneIndicesArray;
delete[] _writeBoneWeightsArray;
glDeleteBuffers(1, &_vboBoneIndicesID);
glDeleteBuffers(1, &_vboBoneWeightsID);
}
}
ProgramObject AvatarVoxelSystem::_skinProgram;
int AvatarVoxelSystem::_boneMatricesLocation;
int AvatarVoxelSystem::_boneIndicesLocation;
int AvatarVoxelSystem::_boneWeightsLocation;
void AvatarVoxelSystem::init() {
if (_initialized) {
qDebug("[ERROR] AvatarVoxelSystem is already initialized.\n");
return;
}
VoxelSystem::init();
// prep the data structures for incoming voxel data
_writeBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels];
_readBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels];
_writeBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels];
_readBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels];
// VBO for the boneIndicesArray
glGenBuffers(1, &_vboBoneIndicesID);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID);
glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
// VBO for the boneWeightsArray
glGenBuffers(1, &_vboBoneWeightsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID);
glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
// load our skin program if this is the first avatar system to initialize
if (!_skinProgram.isLinked()) {
_skinProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_voxels.vert");
_skinProgram.link();
}
_boneMatricesLocation = _skinProgram.uniformLocation("boneMatrices");
_boneIndicesLocation = _skinProgram.attributeLocation("boneIndices");
_boneWeightsLocation = _skinProgram.attributeLocation("boneWeights");
VoxelTreeElement::removeUpdateHook(this); // we don't want this
_initialized = true;
}
void AvatarVoxelSystem::removeOutOfView() {
// no-op for now
}
class Mode {
public:
bool bindVoxelsTogether;
int maxBonesPerBind;
bool includeBonesOutsideBindRadius;
};
const Mode MODES[] = {
{ false, BONE_ELEMENTS_PER_VERTEX, false }, // original
{ false, 1, true }, // one bone per vertex
{ true, 1, true }, // one bone per voxel
{ true, BONE_ELEMENTS_PER_VERTEX, false } }; // four bones per voxel
void AvatarVoxelSystem::cycleMode() {
_mode = (_mode + 1) % (sizeof(MODES) / sizeof(MODES[0]));
qDebug("Voxeltar bind mode %d.\n", _mode);
// rebind
QUrl url = _voxelURL;
setVoxelURL(QUrl());
setVoxelURL(url);
}
void AvatarVoxelSystem::setVoxelURL(const QUrl& url) {
// don't restart the download if it's the same URL
if (_voxelURL == url) {
return;
}
// cancel any current download
if (_voxelReply != 0) {
delete _voxelReply;
_voxelReply = 0;
}
killLocalVoxels();
// remember the URL
_voxelURL = url;
// handle "file://" urls...
if (url.isLocalFile()) {
QString pathString = url.path();
QByteArray pathAsAscii = pathString.toLocal8Bit();
const char* path = pathAsAscii.data();
readFromSVOFile(path);
return;
}
// load the URL data asynchronously
if (!url.isValid()) {
return;
}
_voxelReply = Application::getInstance()->getNetworkAccessManager()->get(QNetworkRequest(url));
connect(_voxelReply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleVoxelDownloadProgress(qint64,qint64)));
connect(_voxelReply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleVoxelReplyError()));
}
void AvatarVoxelSystem::updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex,
float voxelScale, const nodeColor& color) {
VoxelSystem::updateArraysDetails(nodeIndex, startVertex, voxelScale, color);
GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL);
GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL);
if (MODES[_mode].bindVoxelsTogether) {
BoneIndices boneIndices;
glm::vec4 boneWeights;
computeBoneIndicesAndWeights(startVertex + glm::vec3(voxelScale, voxelScale, voxelScale) * 0.5f,
boneIndices, boneWeights);
for (int i = 0; i < VERTICES_PER_VOXEL; i++) {
for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) {
*(writeBoneIndicesAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneIndices[j];
*(writeBoneWeightsAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneWeights[j];
}
}
} else {
for (int i = 0; i < VERTICES_PER_VOXEL; i++) {
BoneIndices boneIndices;
glm::vec4 boneWeights;
computeBoneIndicesAndWeights(computeVoxelVertex(startVertex, voxelScale, i), boneIndices, boneWeights);
for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) {
*(writeBoneIndicesAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneIndices[j];
*(writeBoneWeightsAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneWeights[j];
}
}
}
}
void AvatarVoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
VoxelSystem::copyWrittenDataSegmentToReadArrays(segmentStart, segmentEnd);
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte);
GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
memcpy(readBoneIndicesAt, writeBoneIndicesAt, segmentSizeBytes);
segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat);
segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes);
}
void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
VoxelSystem::updateVBOSegment(segmentStart, segmentEnd);
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte);
GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneIndicesFrom);
segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat);
segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom);
}
void AvatarVoxelSystem::applyScaleAndBindProgram(bool texture) {
_skinProgram.bind();
// the base matrix includes centering and scale
QMatrix4x4 baseMatrix;
baseMatrix.scale(_treeScale);
baseMatrix.translate(-0.5f, -0.5f, -0.5f);
// bone matrices include joint transforms
QMatrix4x4 boneMatrices[NUM_AVATAR_JOINTS];
for (int i = 0; i < NUM_AVATAR_JOINTS; i++) {
glm::vec3 position;
glm::quat orientation;
_avatar->getBodyBallTransform((AvatarJointID)i, position, orientation);
boneMatrices[i].translate(position.x, position.y, position.z);
orientation = orientation * glm::inverse(_avatar->getSkeleton().joint[i].absoluteBindPoseRotation);
boneMatrices[i].rotate(QQuaternion(orientation.w, orientation.x, orientation.y, orientation.z));
const glm::vec3& bindPosition = _avatar->getSkeleton().joint[i].absoluteBindPosePosition;
boneMatrices[i].translate(-bindPosition.x, -bindPosition.y, -bindPosition.z);
boneMatrices[i] *= baseMatrix;
}
_skinProgram.setUniformValueArray(_boneMatricesLocation, boneMatrices, NUM_AVATAR_JOINTS);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID);
glVertexAttribPointer(_boneIndicesLocation, BONE_ELEMENTS_PER_VERTEX, GL_UNSIGNED_BYTE, false, 0, 0);
_skinProgram.enableAttributeArray(_boneIndicesLocation);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID);
_skinProgram.setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_ELEMENTS_PER_VERTEX);
_skinProgram.enableAttributeArray(_boneWeightsLocation);
}
void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) {
_skinProgram.release();
_skinProgram.disableAttributeArray(_boneIndicesLocation);
_skinProgram.disableAttributeArray(_boneWeightsLocation);
}
void AvatarVoxelSystem::handleVoxelDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
// for now, just wait until we have the full business
if (bytesReceived < bytesTotal) {
return;
}
QByteArray entirety = _voxelReply->readAll();
_voxelReply->disconnect(this);
_voxelReply->deleteLater();
_voxelReply = 0;
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS);
_tree->readBitstreamToTree((unsigned char*)entirety.data(), entirety.size(), args);
setupNewVoxelsForDrawing();
}
void AvatarVoxelSystem::handleVoxelReplyError() {
qDebug("%s\n", _voxelReply->errorString().toLocal8Bit().constData());
_voxelReply->disconnect(this);
_voxelReply->deleteLater();
_voxelReply = 0;
}
class IndexDistance {
public:
IndexDistance(GLubyte index = AVATAR_JOINT_PELVIS, float distance = FLT_MAX) : index(index), distance(distance) { }
GLubyte index;
float distance;
};
void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const {
// transform into joint space
glm::vec3 jointVertex = (vertex - glm::vec3(0.5f, 0.5f, 0.5f)) * AVATAR_TREE_SCALE;
// find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up)
IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX];
const Skeleton& skeleton = _avatar->getSkeleton();
for (int i = 0; i < NUM_AVATAR_JOINTS; i++) {
AvatarJointID parent = skeleton.joint[i].parent;
float distance = glm::length(computeVectorFromPointToSegment(jointVertex,
skeleton.joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition,
skeleton.joint[i].absoluteBindPosePosition));
if (!MODES[_mode].includeBonesOutsideBindRadius && distance > skeleton.joint[i].bindRadius) {
continue;
}
for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) {
if (distance < nearest[j].distance) {
// move the rest of the indices down
for (int k = BONE_ELEMENTS_PER_VERTEX - 1; k > j; k--) {
nearest[k] = nearest[k - 1];
}
nearest[j] = IndexDistance(i, distance);
break;
}
}
}
// compute the weights based on inverse distance
float totalWeight = 0.0f;
for (int i = 0; i < MODES[_mode].maxBonesPerBind; i++) {
indices[i] = nearest[i].index;
if (nearest[i].distance != FLT_MAX) {
weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON);
totalWeight += weights[i];
} else {
weights[i] = 0.0f;
}
}
// if it's not attached to anything, consider it attached to the hip
if (totalWeight == 0.0f) {
weights[0] = 1.0f;
return;
}
// ortherwise, normalize the weights
for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) {
weights[i] /= totalWeight;
}
}

View file

@ -1,84 +0,0 @@
//
// AvatarVoxelSystem.h
// interface
//
// Created by Andrzej Kapolka on 5/31/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__AvatarVoxelSystem__
#define __interface__AvatarVoxelSystem__
#include <QObject>
#include <QUrl>
#include "VoxelSystem.h"
const int BONE_ELEMENTS_PER_VERTEX = 4;
typedef GLubyte BoneIndices[BONE_ELEMENTS_PER_VERTEX];
class QNetworkReply;
class Avatar;
class AvatarVoxelSystem : public VoxelSystem {
Q_OBJECT
public:
AvatarVoxelSystem(Avatar* avatar);
virtual ~AvatarVoxelSystem();
virtual void init();
virtual void removeOutOfView();
Q_INVOKABLE void setVoxelURL(const QUrl& url);
const QUrl& getVoxelURL() const { return _voxelURL; }
public slots:
void cycleMode();
protected:
virtual void updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex,
float voxelScale, const nodeColor& color);
virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd);
virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd);
virtual void applyScaleAndBindProgram(bool texture);
virtual void removeScaleAndReleaseProgram(bool texture);
private slots:
void handleVoxelDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void handleVoxelReplyError();
private:
void computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const;
bool _initialized;
int _mode;
Avatar* _avatar;
QUrl _voxelURL;
GLubyte* _readBoneIndicesArray;
GLfloat* _readBoneWeightsArray;
GLubyte* _writeBoneIndicesArray;
GLfloat* _writeBoneWeightsArray;
GLuint _vboBoneIndicesID;
GLuint _vboBoneWeightsID;
QNetworkReply* _voxelReply;
static ProgramObject _skinProgram;
static int _boneMatricesLocation;
static int _boneIndicesLocation;
static int _boneWeightsLocation;
};
#endif /* defined(__interface__AvatarVoxelSystem__) */

View file

@ -24,6 +24,7 @@
#include "ParticleSystem.h"
#include "world.h"
#include "devices/SerialInterface.h"
#include "VoxelSystem.h"
class Avatar;
class ProgramObject;

View file

@ -250,9 +250,8 @@ void Head::simulate(float deltaTime, bool isMine) {
calculateGeometry();
// the blend face may have custom eye meshes
if (!Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)) {
_faceModel.getEyePositions(_leftEyePosition, _rightEyePosition);
}
}
void Head::calculateGeometry() {

View file

@ -32,7 +32,6 @@ const float COLLISION_RADIUS_SCALAR = 1.2; // pertains to avatar-to-avatar colli
const float COLLISION_BALL_FORCE = 200.0; // pertains to avatar-to-avatar collisions
const float COLLISION_BODY_FORCE = 30.0; // pertains to avatar-to-avatar collisions
const float COLLISION_RADIUS_SCALE = 0.125f;
const float PERIPERSONAL_RADIUS = 1.0f;
const float MOUSE_RAY_TOUCH_RANGE = 0.01f;
const bool USING_HEAD_LEAN = false;
const float SKIN_COLOR[] = {1.0, 0.84, 0.66};
@ -46,7 +45,6 @@ MyAvatar::MyAvatar(Node* owningNode) :
_shouldJump(false),
_gravity(0.0f, -1.0f, 0.0f),
_distanceToNearestAvatar(std::numeric_limits<float>::max()),
_interactingOther(NULL),
_elapsedTimeMoving(0.0f),
_elapsedTimeStopped(0.0f),
_elapsedTimeSinceCollision(0.0f),
@ -77,8 +75,6 @@ void MyAvatar::setMoveTarget(const glm::vec3 moveTarget) {
void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
glm::quat orientation = getOrientation();
glm::vec3 front = orientation * IDENTITY_FRONT;
glm::vec3 right = orientation * IDENTITY_RIGHT;
// Update movement timers
_elapsedTimeSinceCollision += deltaTime;
@ -115,9 +111,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
// calculate speed
_speed = glm::length(_velocity);
// figure out if the mouse cursor is over any body spheres...
checkForMouseRayTouching();
// update balls
if (_balls) {
_balls->moveOrigin(_position);
@ -143,30 +136,8 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
enableHandMovement &= (it->jointID != AVATAR_JOINT_RIGHT_WRIST);
}
// update avatar skeleton
_skeleton.update(deltaTime, getOrientation(), _position);
// determine the lengths of the body springs now that we have updated the skeleton at least once
if (!_ballSpringsInitialized) {
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
glm::vec3 targetPosition
= _skeleton.joint[_bodyBall[b].parentJoint].position
+ _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset;
glm::vec3 parentTargetPosition
= _skeleton.joint[_bodyBall[b].parentJoint].position
+ _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset;
_bodyBall[b].springLength = glm::length(targetPosition - parentTargetPosition);
}
_ballSpringsInitialized = true;
}
// update the movement of the hand and process handshaking with other avatars...
updateHandMovementAndTouching(deltaTime, enableHandMovement);
_avatarTouch.simulate(deltaTime);
// apply gravity
// For gravity, always move the avatar by the amount driven by gravity, so that the collision
@ -193,9 +164,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
updateAvatarCollisions(deltaTime);
}
// update body balls
updateBodyBalls(deltaTime);
// add thrust to velocity
_velocity += _thrust * deltaTime;
@ -238,30 +206,9 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
applyDamping(deltaTime, _velocity, linearDamping, SQUARED_DAMPING_STRENGTH);
}
// pitch and roll the body as a function of forward speed and turning delta
const float HIGH_VELOCITY = 10.f;
if (glm::length(_velocity) < HIGH_VELOCITY) {
const float BODY_PITCH_WHILE_WALKING = -20.0;
const float BODY_ROLL_WHILE_TURNING = 0.2;
float forwardComponentOfVelocity = glm::dot(getBodyFrontDirection(), _velocity);
orientation = orientation * glm::quat(glm::radians(glm::vec3(
BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity, 0.0f,
BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta)));
}
// these forces keep the body upright...
const float BODY_UPRIGHT_FORCE = _scale * 10.0;
float tiltDecay = BODY_UPRIGHT_FORCE * deltaTime;
if (tiltDecay > 1.0f) {
tiltDecay = 1.0f;
}
// update the euler angles
setOrientation(orientation);
//the following will be used to make the avatar upright no matter what gravity is
setOrientation(computeRotationFromBodyToWorldUp(tiltDecay) * orientation);
// Compute instantaneous acceleration
float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime;
const float ACCELERATION_PITCH_DECAY = 0.4f;
@ -295,44 +242,6 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
}
}
//apply the head lean values to the ball positions...
if (USING_HEAD_LEAN) {
if (fabs(_head.getLeanSideways() + _head.getLeanForward()) > 0.0f) {
glm::vec3 headLean =
right * _head.getLeanSideways() +
front * _head.getLeanForward();
_bodyBall[BODY_BALL_TORSO].position += headLean * 0.1f;
_bodyBall[BODY_BALL_CHEST].position += headLean * 0.4f;
_bodyBall[BODY_BALL_NECK_BASE].position += headLean * 0.7f;
_bodyBall[BODY_BALL_HEAD_BASE].position += headLean * 1.0f;
_bodyBall[BODY_BALL_LEFT_COLLAR].position += headLean * 0.6f;
_bodyBall[BODY_BALL_LEFT_SHOULDER].position += headLean * 0.6f;
_bodyBall[BODY_BALL_LEFT_ELBOW].position += headLean * 0.2f;
_bodyBall[BODY_BALL_LEFT_WRIST].position += headLean * 0.1f;
_bodyBall[BODY_BALL_LEFT_FINGERTIPS].position += headLean * 0.0f;
_bodyBall[BODY_BALL_RIGHT_COLLAR].position += headLean * 0.6f;
_bodyBall[BODY_BALL_RIGHT_SHOULDER].position += headLean * 0.6f;
_bodyBall[BODY_BALL_RIGHT_ELBOW].position += headLean * 0.2f;
_bodyBall[BODY_BALL_RIGHT_WRIST].position += headLean * 0.1f;
_bodyBall[BODY_BALL_RIGHT_FINGERTIPS].position += headLean * 0.0f;
}
}
_hand.simulate(deltaTime, true);
_skeletonModel.simulate(deltaTime);
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
glm::vec3 headPosition;
if (Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls) || !_skeletonModel.getHeadPosition(headPosition)) {
headPosition = _bodyBall[BODY_BALL_HEAD_BASE].position;
}
_head.setPosition(headPosition);
_head.setScale(_scale);
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
_head.simulate(deltaTime, true);
const float WALKING_SPEED_THRESHOLD = 0.2f;
// use speed and angular velocity to determine walking vs. standing
if (_speed + fabs(_bodyYawDelta) > WALKING_SPEED_THRESHOLD) {
@ -364,6 +273,18 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
_position += _velocity * deltaTime;
// update avatar skeleton and simulate hand and head
_skeleton.update(deltaTime, getOrientation(), _position);
_hand.simulate(deltaTime, true);
_skeletonModel.simulate(deltaTime);
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
glm::vec3 headPosition;
_skeletonModel.getHeadPosition(headPosition);
_head.setPosition(headPosition);
_head.setScale(_scale);
_head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]));
_head.simulate(deltaTime, true);
// Zero thrust out now that we've added it to velocity in this frame
_thrust = glm::vec3(0, 0, 0);
@ -499,15 +420,9 @@ static TextRenderer* textRenderer() {
void MyAvatar::render(bool forceRenderHead) {
// render a simple round on the ground projected down from the avatar's position
renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f), _scale * 0.1f, 0.2f);
// render body
renderBody(forceRenderHead);
// if this is my avatar, then render my interactions with the other avatar
_avatarTouch.render(Application::getInstance()->getCamera()->getPosition());
// Render the balls
if (_balls) {
glPushMatrix();
@ -523,7 +438,7 @@ void MyAvatar::render(bool forceRenderHead) {
}
glPushMatrix();
glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight * _scale;
glm::vec3 chatPosition = getPosition() + getBodyUpDirection() * chatMessageHeight * _scale;
glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z);
glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation();
glm::vec3 chatAxis = glm::axis(chatRotation);
@ -571,7 +486,6 @@ void MyAvatar::saveData(QSettings* settings) {
settings->setValue("position_y", _position.y);
settings->setValue("position_z", _position.z);
settings->setValue("voxelURL", _voxels.getVoxelURL());
settings->setValue("pupilDilation", _head.getPupilDilation());
settings->setValue("leanScale", _leanScale);
@ -594,7 +508,6 @@ void MyAvatar::loadData(QSettings* settings) {
_position.y = loadSetting(settings, "position_y", 0.0f);
_position.z = loadSetting(settings, "position_z", 0.0f);
_voxels.setVoxelURL(settings->value("voxelURL").toUrl());
_head.setPupilDilation(settings->value("pupilDilation", 0.0f).toFloat());
_leanScale = loadSetting(settings, "leanScale", 0.05f);
@ -621,93 +534,15 @@ glm::vec3 MyAvatar::getEyeLevelPosition() const {
glm::vec3(0.0f, _pelvisToHeadLength + _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_UP_OFFSET, 0.0f);
}
float MyAvatar::getBallRenderAlpha(int ball, bool forceRenderHead) const {
const float RENDER_OPAQUE_OUTSIDE = _scale * 0.25f; // render opaque if greater than this distance
const float DO_NOT_RENDER_INSIDE = _scale * 0.25f; // do not render if less than this distance
float distanceToCamera = glm::length(Application::getInstance()->getCamera()->getPosition() - _bodyBall[ball].position);
return (forceRenderHead) ? 1.0f : glm::clamp(
(distanceToCamera - DO_NOT_RENDER_INSIDE) / (RENDER_OPAQUE_OUTSIDE - DO_NOT_RENDER_INSIDE), 0.f, 1.f);
}
void MyAvatar::renderBody(bool forceRenderHead) {
if (_head.getVideoFace().isFullFrame()) {
// Render the full-frame video
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead);
if (alpha > 0.0f) {
_head.getVideoFace().render(1.0f);
}
} else if (Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)) {
// Render the body as balls and cones
glm::vec3 skinColor, darkSkinColor;
getSkinColors(skinColor, darkSkinColor);
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
float alpha = getBallRenderAlpha(b, forceRenderHead);
// When we have leap hands, hide part of the arms.
if (_hand.getNumPalms() > 0) {
if (b == BODY_BALL_LEFT_FINGERTIPS
|| b == BODY_BALL_RIGHT_FINGERTIPS) {
continue;
}
}
// Always render other people, and render myself when beyond threshold distance
if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special
if (alpha > 0.0f) {
_head.render(alpha, true);
}
} else if (alpha > 0.0f) {
// Render the body ball sphere
if (b == BODY_BALL_RIGHT_ELBOW
|| b == BODY_BALL_RIGHT_WRIST
|| b == BODY_BALL_RIGHT_FINGERTIPS ) {
glColor3f(skinColor.r + _bodyBall[b].touchForce * 0.3f,
skinColor.g - _bodyBall[b].touchForce * 0.2f,
skinColor.b - _bodyBall[b].touchForce * 0.1f);
} else {
glColor4f(skinColor.r + _bodyBall[b].touchForce * 0.3f,
skinColor.g - _bodyBall[b].touchForce * 0.2f,
skinColor.b - _bodyBall[b].touchForce * 0.1f,
alpha);
}
if ((b != BODY_BALL_HEAD_TOP )
&& (b != BODY_BALL_HEAD_BASE )) {
glPushMatrix();
glTranslatef(_bodyBall[b].position.x, _bodyBall[b].position.y, _bodyBall[b].position.z);
glutSolidSphere(_bodyBall[b].radius, 20.0f, 20.0f);
glPopMatrix();
}
// Render the cone connecting this ball to its parent
if (_bodyBall[b].parentBall != BODY_BALL_NULL) {
if ((b != BODY_BALL_HEAD_TOP)
&& (b != BODY_BALL_HEAD_BASE)
&& (b != BODY_BALL_PELVIS)
&& (b != BODY_BALL_TORSO)
&& (b != BODY_BALL_CHEST)
&& (b != BODY_BALL_LEFT_COLLAR)
&& (b != BODY_BALL_LEFT_SHOULDER)
&& (b != BODY_BALL_RIGHT_COLLAR)
&& (b != BODY_BALL_RIGHT_SHOULDER)) {
glColor3fv((const GLfloat*)&darkSkinColor);
float r2 = _bodyBall[b].radius * 0.8;
renderJointConnectingCone(_bodyBall[_bodyBall[b].parentBall].position, _bodyBall[b].position, r2, r2);
}
}
}
}
} else {
// Render the body's voxels and head
if (!_skeletonModel.render(1.0f)) {
_voxels.render(false);
}
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead);
if (alpha > 0.0f) {
_head.render(alpha, false);
}
_skeletonModel.render(1.0f);
_head.render(1.0f, false);
}
_hand.render(true);
}
@ -882,90 +717,6 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov
pointing = true;
}
_avatarTouch.setMyBodyPosition(_position);
_avatarTouch.setMyOrientation(orientation);
float closestDistance = std::numeric_limits<float>::max();
_interactingOther = NULL;
//loop through all the other avatars for potential interactions...
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
Avatar *otherAvatar = (Avatar *)node->getLinkedData();
// test whether shoulders are close enough to allow for reaching to touch hands
glm::vec3 v(_position - otherAvatar->_position);
float distance = glm::length(v);
if (distance < closestDistance) {
closestDistance = distance;
if (distance < _scale * PERIPERSONAL_RADIUS) {
_interactingOther = otherAvatar;
}
}
}
}
if (_interactingOther) {
_avatarTouch.setHasInteractingOther(true);
_avatarTouch.setYourBodyPosition(_interactingOther->_position);
_avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position);
_avatarTouch.setYourOrientation (_interactingOther->getOrientation());
_avatarTouch.setYourHandState(_interactingOther->_handState);
//if hand-holding is initiated by either avatar, turn on hand-holding...
if (_avatarTouch.getHandsCloseEnoughToGrasp()) {
if ((_handState == HAND_STATE_GRASPING ) || (_interactingOther->_handState == HAND_STATE_GRASPING)) {
if (!_avatarTouch.getHoldingHands())
{
_avatarTouch.setHoldingHands(true);
}
}
}
glm::vec3 vectorFromMyHandToYourHand
(
_interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position -
_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position
);
float distanceBetweenOurHands = glm::length(vectorFromMyHandToYourHand);
// if neither of us are grasping, turn off hand-holding
if ((_handState != HAND_STATE_GRASPING ) && (_interactingOther->_handState != HAND_STATE_GRASPING)) {
_avatarTouch.setHoldingHands(false);
}
//if holding hands, apply the appropriate forces
if (_avatarTouch.getHoldingHands()) {
_skeleton.joint[AVATAR_JOINT_RIGHT_FINGERTIPS ].position +=
(_interactingOther->_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position
- _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position) * 0.5f;
const float MAX_FORCE = 1.0f;
const float FORCE_RATIO = 10.0f;
if (distanceBetweenOurHands > 0.3) {
float force = min(MAX_FORCE, FORCE_RATIO * deltaTime);
_velocity += vectorFromMyHandToYourHand * force;
}
}
} else {
_avatarTouch.setHasInteractingOther(false);
}
enableHandMovement |= updateLeapHandPositions();
//constrain right arm length and re-adjust elbow position as it bends
// NOTE - the following must be called on all avatars - not just _isMine
if (enableHandMovement) {
updateArmIKAndConstraints(deltaTime, AVATAR_JOINT_RIGHT_FINGERTIPS);
updateArmIKAndConstraints(deltaTime, AVATAR_JOINT_LEFT_FINGERTIPS);
}
//Set right hand position and state to be transmitted, and also tell AvatarTouch about it
setHandPosition(_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
@ -976,9 +727,6 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov
} else {
_handState = HAND_STATE_NULL;
}
_avatarTouch.setMyHandState(_handState);
_avatarTouch.setMyHandPosition(_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position);
}
void MyAvatar::updateCollisionWithEnvironment(float deltaTime) {
@ -1076,72 +824,11 @@ void MyAvatar::updateAvatarCollisions(float deltaTime) {
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
Avatar *otherAvatar = (Avatar *)node->getLinkedData();
// check if the bounding spheres of the two avatars are colliding
glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position);
if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) {
// apply forces from collision
applyCollisionWithOtherAvatar(otherAvatar, deltaTime);
}
// test other avatar hand position for proximity
glm::vec3 v(_skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position);
v -= otherAvatar->getPosition();
float distance = glm::length(v);
if (distance < _distanceToNearestAvatar) {
_distanceToNearestAvatar = distance;
//Avatar *otherAvatar = (Avatar *)node->getLinkedData();
//
// Placeholder: Add code here when we want to add Avatar<->Avatar collision stuff
}
}
}
}
// detect collisions with other avatars and respond
void MyAvatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) {
// for now, don't collide if we have a new skeleton
if (_skeletonModel.isActive()) {
return;
}
glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f);
// loop through the body balls of each avatar to check for every possible collision
for (int b = 1; b < NUM_AVATAR_BODY_BALLS; b++) {
if (_bodyBall[b].isCollidable) {
for (int o = b+1; o < NUM_AVATAR_BODY_BALLS; o++) {
if (otherAvatar->_bodyBall[o].isCollidable) {
glm::vec3 vectorBetweenBalls(_bodyBall[b].position - otherAvatar->_bodyBall[o].position);
float distanceBetweenBalls = glm::length(vectorBetweenBalls);
if (distanceBetweenBalls > 0.0) { // to avoid divide by zero
float combinedRadius = _bodyBall[b].radius + otherAvatar->_bodyBall[o].radius;
// check for collision
if (distanceBetweenBalls < combinedRadius * COLLISION_RADIUS_SCALAR) {
glm::vec3 directionVector = vectorBetweenBalls / distanceBetweenBalls;
// push balls away from each other and apply friction
float penetration = 1.0f - (distanceBetweenBalls / (combinedRadius * COLLISION_RADIUS_SCALAR));
glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * penetration * deltaTime;
bodyPushForce += directionVector * COLLISION_BODY_FORCE * penetration * deltaTime;
_bodyBall[b].velocity += ballPushForce;
otherAvatar->_bodyBall[o].velocity -= ballPushForce;
}// check for collision
} // to avoid divide by zero
} // o loop
} // collidable
} // b loop
} // collidable
// apply force on the whole body
_velocity += bodyPushForce;
}
class SortedAvatar {
@ -1262,23 +949,6 @@ void MyAvatar::setGravity(glm::vec3 gravity) {
}
}
void MyAvatar::checkForMouseRayTouching() {
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
glm::vec3 directionToBodySphere = glm::normalize(_bodyBall[b].position - _mouseRayOrigin);
float dot = glm::dot(directionToBodySphere, _mouseRayDirection);
float range = _bodyBall[b].radius * MOUSE_RAY_TOUCH_RANGE;
if (dot > (1.0f - range)) {
_bodyBall[b].touchForce = (dot - (1.0f - range)) / range;
} else {
_bodyBall[b].touchForce = 0.0;
}
}
}
void MyAvatar::setOrientation(const glm::quat& orientation) {
glm::vec3 eulerAngles = safeEulerAngles(orientation);
_bodyPitch = eulerAngles.x;

View file

@ -13,6 +13,15 @@
#include "Avatar.h"
enum AvatarHandState
{
HAND_STATE_NULL = 0,
HAND_STATE_OPEN,
HAND_STATE_GRASPING,
HAND_STATE_POINTING,
NUM_HAND_STATES
};
class MyAvatar : public Avatar {
public:
MyAvatar(Node* owningNode = NULL);
@ -67,7 +76,6 @@ private:
float _driveKeys[MAX_DRIVE_KEYS];
glm::vec3 _gravity;
float _distanceToNearestAvatar; // How close is the nearest avatar?
Avatar* _interactingOther;
float _elapsedTimeMoving; // Timers to drive camera transitions when moving
float _elapsedTimeStopped;
float _elapsedTimeSinceCollision;
@ -80,7 +88,6 @@ private:
int _moveTargetStepCounter;
// private methods
float getBallRenderAlpha(int ball, bool forceRenderHead) const;
void renderBody(bool forceRenderHead);
void updateThrust(float deltaTime, Transmitter * transmitter);
void updateHandMovementAndTouching(float deltaTime, bool enableHandMovement);
@ -89,9 +96,7 @@ private:
void updateCollisionWithVoxels(float deltaTime);
void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping);
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime );
void updateChatCircle(float deltaTime);
void checkForMouseRayTouching();
};
#endif

View file

@ -61,6 +61,7 @@ void SkeletonModel::simulate(float deltaTime) {
}
bool SkeletonModel::render(float alpha) {
if (_jointStates.isEmpty()) {
return false;
}

View file

@ -29,10 +29,13 @@ int main(int argc, const char * argv[]) {
QCoreApplication::addLibraryPath(QT_RELEASE_PLUGIN_PATH);
#endif
int exitCode;
{
Application app(argc, const_cast<char**>(argv), startup_time);
qDebug( "Created QT Application.\n" );
int exitCode = app.exec();
exitCode = app.exec();
}
qDebug("Normal exit.\n");
return exitCode;
}

View file

@ -582,6 +582,7 @@ class ExtractedMesh {
public:
FBXMesh mesh;
QMultiHash<int, int> newIndices;
QVector<QHash<int, int> > blendshapeIndexMaps;
};
class MeshData {
@ -780,7 +781,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
QVector<QString> jointRightFingertipIDs(jointRightFingertipNames.size());
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
QHash<QByteArray, QPair<int, float> > blendshapeIndices;
typedef QPair<int, float> WeightedIndex;
QMultiHash<QByteArray, WeightedIndex> blendshapeIndices;
for (int i = 0;; i++) {
QByteArray blendshapeName = FACESHIFT_BLENDSHAPES[i];
if (blendshapeName.isEmpty()) {
@ -788,16 +790,16 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
}
QList<QVariant> mappings = blendshapeMappings.values(blendshapeName);
if (mappings.isEmpty()) {
blendshapeIndices.insert(blendshapeName, QPair<int, float>(i, 1.0f));
blendshapeIndices.insert(blendshapeName, WeightedIndex(i, 1.0f));
} else {
foreach (const QVariant& mapping, mappings) {
QVariantList blendshapeMapping = mapping.toList();
blendshapeIndices.insert(blendshapeMapping.at(0).toByteArray(),
QPair<int, float>(i, blendshapeMapping.at(1).toFloat()));
WeightedIndex(i, blendshapeMapping.at(1).toFloat()));
}
}
}
QHash<QString, QPair<int, float> > blendshapeChannelIndices;
QMultiHash<QString, WeightedIndex> blendshapeChannelIndices;
foreach (const FBXNode& child, node.children) {
if (child.name == "Objects") {
@ -1033,7 +1035,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
// try everything after the dot
name = name.mid(name.lastIndexOf('.') + 1);
}
blendshapeChannelIndices.insert(getID(object.properties), blendshapeIndices.value(name));
QString id = getID(object.properties);
foreach (const WeightedIndex& index, blendshapeIndices.values(name)) {
blendshapeChannelIndices.insert(id, index);
}
}
}
}
@ -1059,19 +1064,29 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
// assign the blendshapes to their corresponding meshes
foreach (const ExtractedBlendshape& extracted, blendshapes) {
QString blendshapeChannelID = parentMap.value(extracted.id);
QPair<int, float> index = blendshapeChannelIndices.value(blendshapeChannelID);
QString blendshapeID = parentMap.value(blendshapeChannelID);
QString meshID = parentMap.value(blendshapeID);
ExtractedMesh& extractedMesh = meshes[meshID];
foreach (const WeightedIndex& index, blendshapeChannelIndices.values(blendshapeChannelID)) {
extractedMesh.mesh.blendshapes.resize(max(extractedMesh.mesh.blendshapes.size(), index.first + 1));
extractedMesh.blendshapeIndexMaps.resize(extractedMesh.mesh.blendshapes.size());
FBXBlendshape& blendshape = extractedMesh.mesh.blendshapes[index.first];
QHash<int, int>& blendshapeIndexMap = extractedMesh.blendshapeIndexMaps[index.first];
for (int i = 0; i < extracted.blendshape.indices.size(); i++) {
int oldIndex = extracted.blendshape.indices.at(i);
for (QMultiHash<int, int>::const_iterator it = extractedMesh.newIndices.constFind(oldIndex);
it != extractedMesh.newIndices.constEnd() && it.key() == oldIndex; it++) {
QHash<int, int>::iterator blendshapeIndex = blendshapeIndexMap.find(it.value());
if (blendshapeIndex == blendshapeIndexMap.end()) {
blendshapeIndexMap.insert(it.value(), blendshape.indices.size());
blendshape.indices.append(it.value());
blendshape.vertices.append(extracted.blendshape.vertices.at(i) * index.second);
blendshape.normals.append(extracted.blendshape.normals.at(i) * index.second);
} else {
blendshape.vertices[*blendshapeIndex] += extracted.blendshape.vertices.at(i) * index.second;
blendshape.normals[*blendshapeIndex] += extracted.blendshape.normals.at(i) * index.second;
}
}
}
}
}

View file

@ -19,6 +19,7 @@ GlowEffect::GlowEffect()
: _initialized(false),
_renderMode(DIFFUSE_ADD_MODE),
_isOddFrame(false),
_isFirstFrame(true),
_intensity(0.0f) {
}
@ -166,6 +167,10 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
}
newDiffusedFBO->bind();
if (_isFirstFrame) {
glClear(GL_COLOR_BUFFER_BIT);
} else {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture());
@ -176,6 +181,7 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
renderFullscreenQuad();
_diffuseProgram->release();
}
newDiffusedFBO->release();
@ -221,7 +227,7 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
maybeRelease(destFBO);
} else { // _renderMode == BLUR_PERSIST_ADD_MODE
// render the secondary to the tertiary with horizontal blur and persistence
// render the secondary to the tertiary with vertical blur and persistence
QOpenGLFramebufferObject* tertiaryFBO =
Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject();
tertiaryFBO->bind();
@ -229,7 +235,7 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA);
const float PERSISTENCE_SMOOTHING = 0.9f;
glBlendColor(0.0f, 0.0f, 0.0f, PERSISTENCE_SMOOTHING);
glBlendColor(0.0f, 0.0f, 0.0f, _isFirstFrame ? 0.0f : PERSISTENCE_SMOOTHING);
glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture());
@ -270,6 +276,8 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
glDepthMask(GL_TRUE);
glBindTexture(GL_TEXTURE_2D, 0);
_isFirstFrame = false;
return destFBO;
}
@ -292,6 +300,7 @@ void GlowEffect::cycleRenderMode() {
qDebug() << "Glow mode: Diffuse/add\n";
break;
}
_isFirstFrame = true;
}
Glower::Glower(float amount) {

View file

@ -66,6 +66,7 @@ private:
bool _isEmpty; ///< set when nothing in the scene is currently glowing
bool _isOddFrame; ///< controls the alternation between texture targets in diffuse add mode
bool _isFirstFrame; ///< for persistent modes, notes whether this is the first frame rendered
float _intensity;
QStack<float> _intensityStack;

View file

@ -263,6 +263,9 @@ bool Model::render(float alpha) {
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5f);
for (int i = 0; i < networkMeshes.size(); i++) {
const NetworkMesh& networkMesh = networkMeshes.at(i);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, networkMesh.indexBufferID);
@ -443,6 +446,8 @@ bool Model::render(float alpha) {
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_ALPHA_TEST);
// bind with 0 to switch back to normal operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);