diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 500c432cef..1131591cfc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -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,16 +379,18 @@ 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))); } - + // Update camera position _myCamera.update( 1.f/_fps ); @@ -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,13 +1427,17 @@ void Application::processAvatarURLsMessage(unsigned char* packetData, size_t dat if (!avatar) { return; } - QDataStream in(QByteArray((char*)packetData, dataBytes)); - QUrl voxelURL; - in >> voxelURL; - - // invoke the set URL functions on the simulate/render thread - QMetaObject::invokeMethod(avatar->getVoxels(), "setVoxelURL", Q_ARG(QUrl, 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. + //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, avatar->getUUID()); @@ -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), diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 50fb0beed8..13510067cd 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -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, @@ -781,11 +774,7 @@ 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); @@ -868,12 +857,7 @@ void Menu::editPreferences() { DataServerClient::putValueForKey(DataServerKey::SkeletonURL, 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(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 84f48e2ffa..aa3b925517 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -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"; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 476e77cd97..f691d54a75 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -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; igetOwningNode()->isAlive()) { follow(NULL); } - + if (_scale != _newScale) { setScale(_newScale); } // copy velocity so we can use it later for acceleration glm::vec3 oldVelocity = getVelocity(); - + // update balls if (_balls) { _balls->moveOrigin(_position); @@ -325,7 +194,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { // update torso rotation based on head lean _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(glm::vec3( - _head.getLeanForward(), 0.0f, _head.getLeanSideways()))); + _head.getLeanForward(), 0.0f, _head.getLeanSideways()))); // apply joint data (if any) to skeleton bool enableHandMovement = true; @@ -338,73 +207,24 @@ 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])); _head.simulate(deltaTime, false); - + // use speed and angular velocity to determine walking vs. standing if (_speed + fabs(_bodyYawDelta) > 0.2) { _mode = AVATAR_MODE_WALKING; @@ -412,12 +232,12 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _mode = AVATAR_MODE_INTERACTING; } - // update position by velocity, and subtract the change added earlier for gravity + // update position by velocity, and subtract the change added earlier for gravity _position += _velocity * deltaTime; // Zero thrust out now that we've added it to velocity in this frame _thrust = glm::vec3(0, 0, 0); - + } void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) { @@ -443,9 +263,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 @@ -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); - } - } - } - } + _head.getVideoFace().render(1.0f); } 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); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 774e98be67..c435191a18 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -15,8 +15,6 @@ #include -#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); diff --git a/interface/src/avatar/AvatarTouch.cpp b/interface/src/avatar/AvatarTouch.cpp deleted file mode 100644 index 78a63bd3aa..0000000000 --- a/interface/src/avatar/AvatarTouch.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// -// AvatarTouch.cpp -// interface -// -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. - -#include -#include -#include -#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 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 -#include - -#include - -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 diff --git a/interface/src/avatar/AvatarVoxelSystem.cpp b/interface/src/avatar/AvatarVoxelSystem.cpp deleted file mode 100644 index 1685187c57..0000000000 --- a/interface/src/avatar/AvatarVoxelSystem.cpp +++ /dev/null @@ -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 - -#include - -#include - -#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; - } -} diff --git a/interface/src/avatar/AvatarVoxelSystem.h b/interface/src/avatar/AvatarVoxelSystem.h deleted file mode 100644 index 2560af11a5..0000000000 --- a/interface/src/avatar/AvatarVoxelSystem.h +++ /dev/null @@ -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 -#include - -#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__) */ diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 46dca6d0cf..12d6d0d8da 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -24,6 +24,7 @@ #include "ParticleSystem.h" #include "world.h" #include "devices/SerialInterface.h" +#include "VoxelSystem.h" class Avatar; class ProgramObject; diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 5dd59ed159..b593602e3f 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -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); - } + _faceModel.getEyePositions(_leftEyePosition, _rightEyePosition); + } void Head::calculateGeometry() { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 51b8b37007..c65c6d50a3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -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::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); @@ -498,16 +419,10 @@ 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::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,74 +824,13 @@ 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 { public: Avatar* avatar; @@ -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; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9f440a50bf..df8ab4aa92 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -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 diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 2605c8438f..b8c500d3bd 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -61,6 +61,7 @@ void SkeletonModel::simulate(float deltaTime) { } bool SkeletonModel::render(float alpha) { + if (_jointStates.isEmpty()) { return false; } diff --git a/interface/src/main.cpp b/interface/src/main.cpp index c1d9bd778d..31468f1320 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -29,10 +29,13 @@ int main(int argc, const char * argv[]) { QCoreApplication::addLibraryPath(QT_RELEASE_PLUGIN_PATH); #endif - Application app(argc, const_cast(argv), startup_time); + int exitCode; + { + Application app(argc, const_cast(argv), startup_time); - qDebug( "Created QT Application.\n" ); - int exitCode = app.exec(); + qDebug( "Created QT Application.\n" ); + exitCode = app.exec(); + } qDebug("Normal exit.\n"); return exitCode; } diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 61c0ae775b..63e3afc8cf 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -582,6 +582,7 @@ class ExtractedMesh { public: FBXMesh mesh; QMultiHash newIndices; + QVector > blendshapeIndexMaps; }; class MeshData { @@ -780,7 +781,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) QVector jointRightFingertipIDs(jointRightFingertipNames.size()); QVariantHash blendshapeMappings = mapping.value("bs").toHash(); - QHash > blendshapeIndices; + typedef QPair WeightedIndex; + QMultiHash 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 mappings = blendshapeMappings.values(blendshapeName); if (mappings.isEmpty()) { - blendshapeIndices.insert(blendshapeName, QPair(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(i, blendshapeMapping.at(1).toFloat())); + WeightedIndex(i, blendshapeMapping.at(1).toFloat())); } } } - QHash > blendshapeChannelIndices; + QMultiHash 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,20 +1064,30 @@ 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 index = blendshapeChannelIndices.value(blendshapeChannelID); QString blendshapeID = parentMap.value(blendshapeChannelID); QString meshID = parentMap.value(blendshapeID); ExtractedMesh& extractedMesh = meshes[meshID]; - extractedMesh.mesh.blendshapes.resize(max(extractedMesh.mesh.blendshapes.size(), index.first + 1)); - FBXBlendshape& blendshape = extractedMesh.mesh.blendshapes[index.first]; - for (int i = 0; i < extracted.blendshape.indices.size(); i++) { - int oldIndex = extracted.blendshape.indices.at(i); - for (QMultiHash::const_iterator it = extractedMesh.newIndices.constFind(oldIndex); - it != extractedMesh.newIndices.constEnd() && it.key() == oldIndex; it++) { - 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); - } + 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& blendshapeIndexMap = extractedMesh.blendshapeIndexMaps[index.first]; + for (int i = 0; i < extracted.blendshape.indices.size(); i++) { + int oldIndex = extracted.blendshape.indices.at(i); + for (QMultiHash::const_iterator it = extractedMesh.newIndices.constFind(oldIndex); + it != extractedMesh.newIndices.constEnd() && it.key() == oldIndex; it++) { + QHash::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; + } + } + } } } diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp index fe46e02688..3bd71b2dd4 100644 --- a/interface/src/renderer/GlowEffect.cpp +++ b/interface/src/renderer/GlowEffect.cpp @@ -19,6 +19,7 @@ GlowEffect::GlowEffect() : _initialized(false), _renderMode(DIFFUSE_ADD_MODE), _isOddFrame(false), + _isFirstFrame(true), _intensity(0.0f) { } @@ -166,16 +167,21 @@ QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { } newDiffusedFBO->bind(); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture()); + if (_isFirstFrame) { + glClear(GL_COLOR_BUFFER_BIT); - _diffuseProgram->bind(); - QSize size = Application::getInstance()->getGLWidget()->size(); - _diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / size.width(), 1.0f / size.height()); + } else { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture()); + + _diffuseProgram->bind(); + QSize size = Application::getInstance()->getGLWidget()->size(); + _diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / size.width(), 1.0f / size.height()); - renderFullscreenQuad(); + renderFullscreenQuad(); - _diffuseProgram->release(); + _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) { diff --git a/interface/src/renderer/GlowEffect.h b/interface/src/renderer/GlowEffect.h index 8168ae4374..65d3d6c8ce 100644 --- a/interface/src/renderer/GlowEffect.h +++ b/interface/src/renderer/GlowEffect.h @@ -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 _intensityStack; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c0403b6d71..9660c05095 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -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);