From 9ca1bfdfe504cc2630b825a0ce59acbc476c8917 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 30 Jun 2014 18:05:22 -0700 Subject: [PATCH 01/18] add AngularConstraint.* with some unit tests more unit tests to follow --- interface/src/renderer/JointState.cpp | 9 +- interface/src/renderer/JointState.h | 4 + libraries/shared/src/AngularConstraint.cpp | 176 ++++++++++++ libraries/shared/src/AngularConstraint.h | 53 ++++ tests/shared/src/AngularConstraintTests.cpp | 291 ++++++++++++++++++++ tests/shared/src/AngularConstraintTests.h | 21 ++ 6 files changed, 553 insertions(+), 1 deletion(-) create mode 100644 libraries/shared/src/AngularConstraint.cpp create mode 100644 libraries/shared/src/AngularConstraint.h create mode 100644 tests/shared/src/AngularConstraintTests.cpp create mode 100644 tests/shared/src/AngularConstraintTests.h diff --git a/interface/src/renderer/JointState.cpp b/interface/src/renderer/JointState.cpp index e66a2f44e9..3b3c135eb5 100644 --- a/interface/src/renderer/JointState.cpp +++ b/interface/src/renderer/JointState.cpp @@ -11,6 +11,7 @@ #include +#include //#include #include @@ -18,7 +19,13 @@ JointState::JointState() : _animationPriority(0.0f), - _fbxJoint(NULL) { + _fbxJoint(NULL), + _constraint(NULL) { +} + +JointState::~JointState() { + delete _constraint; + _constraint = NULL; } void JointState::setFBXJoint(const FBXJoint* joint) { diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h index b1a584d4ec..4eadc51f7c 100644 --- a/interface/src/renderer/JointState.h +++ b/interface/src/renderer/JointState.h @@ -18,9 +18,12 @@ #include +class AngularConstraint; + class JointState { public: JointState(); + ~JointState(); void setFBXJoint(const FBXJoint* joint); const FBXJoint& getFBXJoint() const { return *_fbxJoint; } @@ -61,6 +64,7 @@ private: glm::quat _rotation; // joint- to model-frame const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint + AngularConstraint* _constraint; }; #endif // hifi_JointState_h diff --git a/libraries/shared/src/AngularConstraint.cpp b/libraries/shared/src/AngularConstraint.cpp new file mode 100644 index 0000000000..bf565d586e --- /dev/null +++ b/libraries/shared/src/AngularConstraint.cpp @@ -0,0 +1,176 @@ +// +// AngularConstraint.cpp +// interface/src/renderer +// +// Created by Andrew Meadows on 2014.05.30 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include // adebug +#include + +#include "AngularConstraint.h" +#include "SharedUtil.h" +#include "StreamUtils.h" // adebug + +// helper function +/// \param angle radian angle to be clamped within angleMin and angleMax +/// \param angleMin minimum value +/// \param angleMax maximum value +/// \return value between minAngle and maxAngle closest to angle +float clampAngle(float angle, float angleMin, float angleMax) { + float minDistance = angle - angleMin; + float maxDistance = angle - angleMax; + if (maxDistance > 0.0f) { + minDistance = glm::min(minDistance, angleMin + TWO_PI - angle); + angle = (minDistance < maxDistance) ? angleMin : angleMax; + } else if (minDistance < 0.0f) { + maxDistance = glm::max(maxDistance, angleMax - TWO_PI - angle); + angle = (minDistance > maxDistance) ? angleMin : angleMax; + } + return angle; +} + +// static +AngularConstraint* AngularConstraint::newAngularConstraint(const glm::vec3& minAngles, const glm::vec3& maxAngles) { + float minDistance2 = glm::distance2(minAngles, glm::vec3(-PI, -PI, -PI)); + float maxDistance2 = glm::distance2(maxAngles, glm::vec3(PI, PI, PI)); + if (minDistance2 < EPSILON && maxDistance2 < EPSILON) { + // no constraint + return NULL; + } + // count the zero length elements + glm::vec3 rangeAngles = maxAngles - minAngles; + int pivotIndex = -1; + int numZeroes = 0; + for (int i = 0; i < 3; ++i) { + if (rangeAngles[i] < EPSILON) { + ++numZeroes; + } else { + pivotIndex = i; + } + } + if (numZeroes == 2) { + // this is a hinge + int forwardIndex = (pivotIndex + 1) % 3; + glm::vec3 forwardAxis(0.0f); + forwardAxis[forwardIndex] = 1.0f; + glm::vec3 rotationAxis(0.0f); + rotationAxis[pivotIndex] = 1.0f; + return new HingeConstraint(forwardAxis, rotationAxis, minAngles[pivotIndex], maxAngles[pivotIndex]); + } else if (numZeroes == 0) { + // approximate the angular limits with a cone roller + // we assume the roll is about z + glm::vec3 middleAngles = 0.5f * (maxAngles - minAngles); + glm::quat yaw = glm::angleAxis(middleAngles[1], glm::vec3(0.0f, 1.0f, 0.0f)); + glm::quat pitch = glm::angleAxis(middleAngles[0], glm::vec3(1.0f, 0.0f, 0.0f)); + glm::vec3 coneAxis = pitch * yaw * glm::vec3(0.0f, 0.0f, 1.0f); + // the coneAngle is half of the average range of the two non-roll rotations + float coneAngle = 0.25f * (middleAngles[0] + middleAngles[1]); + + return new ConeRollerConstraint(coneAngle, coneAxis, minAngles.z, maxAngles.z); + } + return NULL; +} + +HingeConstraint::HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& rotationAxis, float minAngle, float maxAngle) + : _minAngle(minAngle), _maxAngle(maxAngle) { + assert(_minAngle < _maxAngle); + // we accept the rotationAxis direction + assert(glm::length(rotationAxis) > EPSILON); + _rotationAxis = glm::normalize(rotationAxis); + // but we compute the final _forwardAxis + glm::vec3 otherAxis = glm::cross(_rotationAxis, forwardAxis); + assert(glm::length(otherAxis) > EPSILON); + _forwardAxis = glm::normalize(glm::cross(otherAxis, _rotationAxis)); +} + +// virtual +bool HingeConstraint::applyTo(glm::quat& rotation) const { + glm::vec3 forward = rotation * _forwardAxis; + forward -= glm::dot(forward, _rotationAxis) * _rotationAxis; + float length = glm::length(forward); + if (length < EPSILON) { + // infinite number of solutions ==> choose the middle of the contrained range + rotation = glm::angleAxis(0.5f * (_minAngle + _maxAngle), _rotationAxis); + return true; + } + forward /= length; + float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f); + //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length); + float angle = sign * acos(glm::dot(forward, _forwardAxis)); +// std::cout << "adebug forward = " << forward << " _forwardAxis = " << _forwardAxis << " angle = " << angle << std::endl; // adebug + glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis); + if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) { + rotation = newRotation; + return true; + } + return false; +} + +ConeRollerConstraint::ConeRollerConstraint(float coneAngle, const glm::vec3& coneAxis, float minRoll, float maxRoll) + : _coneAngle(coneAngle), _minRoll(minRoll), _maxRoll(maxRoll) { + assert(_maxRoll >= _minRoll); + float axisLength = glm::length(coneAxis); + assert(axisLength > EPSILON); + _coneAxis = coneAxis / axisLength; +} + +// virtual +bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { + bool applied = false; + glm::vec3 rotatedAxis = rotation * _coneAxis; + glm::vec3 perpAxis = glm::cross(rotatedAxis, _coneAxis); + float perpAxisLength = glm::length(perpAxis); + + // enforce the cone + float angle = acosf(glm::dot(rotatedAxis, _coneAxis)); + if (angle > _coneAngle && perpAxisLength > EPSILON) { + perpAxis /= perpAxisLength; + rotation = glm::angleAxis(angle - _coneAngle, perpAxis) * rotation; + rotatedAxis = rotation * _coneAxis; + applied = true; + } + + // enforce the roll + if (perpAxisLength < EPSILON) { + // there is no obvious perp axis so we must pick one + perpAxis = rotatedAxis; + // find the first non-zero element: + float value = 0.0f; + int i = 0; + for (i = 0; i < 3; ++i) { + if (fabsf(perpAxis[i]) > EPSILON) { + value = perpAxis[i]; + break; + } + } + assert(i != 3); + // swap or negate the next element + int j = (i + 1) % 3; + float value2 = perpAxis[j]; + if (fabsf(value2 - value) > EPSILON) { + perpAxis[i] = value2; + perpAxis[j] = value; + } else { + perpAxis[i] = -value; + } + perpAxis = glm::cross(perpAxis, rotatedAxis); + perpAxisLength = glm::length(perpAxis); + assert(perpAxisLength > EPSILON); + } + perpAxis /= perpAxisLength; + glm::vec3 rotatedPerpAxis = rotation * perpAxis; + float roll = angleBetween(rotatedPerpAxis, perpAxis); + if (roll < _minRoll || roll > _maxRoll) { + float newRoll = clampAngle(roll, _minRoll, _maxRoll); + rotation = glm::angleAxis(newRoll - roll, rotatedAxis) * rotation; + applied = true; + } + return applied; +} + + diff --git a/libraries/shared/src/AngularConstraint.h b/libraries/shared/src/AngularConstraint.h new file mode 100644 index 0000000000..8003e4c9a3 --- /dev/null +++ b/libraries/shared/src/AngularConstraint.h @@ -0,0 +1,53 @@ +// +// AngularConstraint.h +// interface/src/renderer +// +// Created by Andrew Meadows on 2014.05.30 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AngularConstraint_h +#define hifi_AngularConstraint_h + +#include + + +class AngularConstraint { +public: + /// \param minAngles minumum euler angles for the constraint + /// \param maxAngles minumum euler angles for the constraint + /// \return pointer to new AngularConstraint of the right type or NULL if none could be made + static AngularConstraint* newAngularConstraint(const glm::vec3& minAngles, const glm::vec3& maxAngles); + + AngularConstraint() {} + virtual ~AngularConstraint() {} + virtual bool applyTo(glm::quat& rotation) const = 0; +protected: +}; + +class HingeConstraint : public AngularConstraint { +public: + HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& rotationAxis, float minAngle, float maxAngle); + virtual bool applyTo(glm::quat& rotation) const; +protected: + glm::vec3 _forwardAxis; + glm::vec3 _rotationAxis; + float _minAngle; + float _maxAngle; +}; + +class ConeRollerConstraint : public AngularConstraint { +public: + ConeRollerConstraint(float coneAngle, const glm::vec3& coneAxis, float minRoll, float maxRoll); + virtual bool applyTo(glm::quat& rotation) const; +private: + float _coneAngle; + glm::vec3 _coneAxis; + float _minRoll; + float _maxRoll; +}; + +#endif // hifi_AngularConstraint_h diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp new file mode 100644 index 0000000000..4c087821c5 --- /dev/null +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -0,0 +1,291 @@ +// +// AngularConstraintTests.cpp +// tests/physics/src +// +// Created by Andrew Meadows on 2014.05.30 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include +#include +#include + +#include "AngularConstraintTests.h" + + +void AngularConstraintTests::testHingeConstraint() { + float minAngle = -PI; + float maxAngle = 0.0f; + glm::vec3 yAxis(0.0f, 1.0f, 0.0f); + glm::vec3 minAngles(0.0f, -PI, 0.0f); + glm::vec3 maxAngles(0.0f, 0.0f, 0.0f); + + AngularConstraint* c = AngularConstraint::newAngularConstraint(minAngles, maxAngles); + if (!c) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: newAngularConstraint() should make a constraint" << std::endl; + } + + { // test in middle of constraint + float angle = 0.5f * (minAngle + maxAngle); + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not change rotation" << std::endl; + } + } + { // test just inside min edge of constraint + float angle = minAngle + 10.f * EPSILON; + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not change rotation" << std::endl; + } + } + { // test just inside max edge of constraint + float angle = maxAngle - 10.f * EPSILON; + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not change rotation" << std::endl; + } + } + { // test just outside min edge of constraint + float angle = minAngle - 0.001f; + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test just outside max edge of constraint + float angle = maxAngle + 0.001f; + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test far outside min edge of constraint (wraps around to max) + float angle = minAngle - 0.75f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test far outside max edge of constraint (wraps around to min) + float angle = maxAngle + 0.75f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + + float ACCEPTABLE_ERROR = 1.0e-4f; + { // test nearby but off-axis rotation + float offAngle = 0.1f; + glm::quat offRotation(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = 0.5f * (maxAngle + minAngle); + glm::quat rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(angle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test way off rotation > maxAngle + float offAngle = 0.5f; + glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = maxAngle + 0.2f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test way off rotation < minAngle + float offAngle = 0.5f; + glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = minAngle - 0.2f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test way off rotation > maxAngle with wrap over to minAngle + float offAngle = -0.5f; + glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = maxAngle + 0.6f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test way off rotation < minAngle with wrap over to maxAngle + float offAngle = -0.6f; + glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = minAngle - 0.7f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } +} + +void AngularConstraintTests::testConeRollerConstraint() { +} + +void AngularConstraintTests::runAllTests() { + testHingeConstraint(); +} diff --git a/tests/shared/src/AngularConstraintTests.h b/tests/shared/src/AngularConstraintTests.h new file mode 100644 index 0000000000..f0994f08c9 --- /dev/null +++ b/tests/shared/src/AngularConstraintTests.h @@ -0,0 +1,21 @@ +// +// AngularConstraintTests.h +// tests/physics/src +// +// Created by Andrew Meadows on 2014.05.30 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AngularConstraintTests_h +#define hifi_AngularConstraintTests_h + +namespace AngularConstraintTests { + void testHingeConstraint(); + void testConeRollerConstraint(); + void runAllTests(); +} + +#endif // hifi_AngularConstraintTests_h From 5934ee5b22bf06fcaae13ed79555dda21a86ff71 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 1 Jul 2014 09:35:47 -0700 Subject: [PATCH 02/18] added tests for ConeRollerConstraint --- libraries/shared/src/AngularConstraint.cpp | 59 +++---- tests/shared/src/AngularConstraintTests.cpp | 183 ++++++++++++++++++++ tests/shared/src/main.cpp | 2 + 3 files changed, 215 insertions(+), 29 deletions(-) diff --git a/libraries/shared/src/AngularConstraint.cpp b/libraries/shared/src/AngularConstraint.cpp index bf565d586e..48649450e1 100644 --- a/libraries/shared/src/AngularConstraint.cpp +++ b/libraries/shared/src/AngularConstraint.cpp @@ -9,12 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include // adebug #include #include "AngularConstraint.h" #include "SharedUtil.h" -#include "StreamUtils.h" // adebug // helper function /// \param angle radian angle to be clamped within angleMin and angleMax @@ -64,13 +62,13 @@ AngularConstraint* AngularConstraint::newAngularConstraint(const glm::vec3& minA } else if (numZeroes == 0) { // approximate the angular limits with a cone roller // we assume the roll is about z - glm::vec3 middleAngles = 0.5f * (maxAngles - minAngles); + glm::vec3 middleAngles = 0.5f * (maxAngles + minAngles); glm::quat yaw = glm::angleAxis(middleAngles[1], glm::vec3(0.0f, 1.0f, 0.0f)); glm::quat pitch = glm::angleAxis(middleAngles[0], glm::vec3(1.0f, 0.0f, 0.0f)); glm::vec3 coneAxis = pitch * yaw * glm::vec3(0.0f, 0.0f, 1.0f); - // the coneAngle is half of the average range of the two non-roll rotations - float coneAngle = 0.25f * (middleAngles[0] + middleAngles[1]); - + // the coneAngle is half the average range of the two non-roll rotations + glm::vec3 range = maxAngles - minAngles; + float coneAngle = 0.25f * (range[0] + range[1]); return new ConeRollerConstraint(coneAngle, coneAxis, minAngles.z, maxAngles.z); } return NULL; @@ -102,7 +100,6 @@ bool HingeConstraint::applyTo(glm::quat& rotation) const { float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f); //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length); float angle = sign * acos(glm::dot(forward, _forwardAxis)); -// std::cout << "adebug forward = " << forward << " _forwardAxis = " << _forwardAxis << " angle = " << angle << std::endl; // adebug glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis); if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) { rotation = newRotation; @@ -125,49 +122,53 @@ bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { glm::vec3 rotatedAxis = rotation * _coneAxis; glm::vec3 perpAxis = glm::cross(rotatedAxis, _coneAxis); float perpAxisLength = glm::length(perpAxis); - - // enforce the cone - float angle = acosf(glm::dot(rotatedAxis, _coneAxis)); - if (angle > _coneAngle && perpAxisLength > EPSILON) { + if (perpAxisLength > EPSILON) { perpAxis /= perpAxisLength; - rotation = glm::angleAxis(angle - _coneAngle, perpAxis) * rotation; - rotatedAxis = rotation * _coneAxis; - applied = true; + // enforce the cone + float angle = acosf(glm::dot(rotatedAxis, _coneAxis)); + if (angle > _coneAngle) { + rotation = glm::angleAxis(angle - _coneAngle, perpAxis) * rotation; + rotatedAxis = rotation * _coneAxis; + applied = true; + } } - - // enforce the roll - if (perpAxisLength < EPSILON) { + else { + // the rotation is 100% roll // there is no obvious perp axis so we must pick one perpAxis = rotatedAxis; // find the first non-zero element: - float value = 0.0f; + float iValue = 0.0f; int i = 0; for (i = 0; i < 3; ++i) { if (fabsf(perpAxis[i]) > EPSILON) { - value = perpAxis[i]; + iValue = perpAxis[i]; break; } } assert(i != 3); // swap or negate the next element int j = (i + 1) % 3; - float value2 = perpAxis[j]; - if (fabsf(value2 - value) > EPSILON) { - perpAxis[i] = value2; - perpAxis[j] = value; + float jValue = perpAxis[j]; + if (fabsf(jValue - iValue) > EPSILON) { + perpAxis[i] = jValue; + perpAxis[j] = iValue; } else { - perpAxis[i] = -value; + perpAxis[i] = -iValue; } perpAxis = glm::cross(perpAxis, rotatedAxis); perpAxisLength = glm::length(perpAxis); assert(perpAxisLength > EPSILON); + perpAxis /= perpAxisLength; } - perpAxis /= perpAxisLength; - glm::vec3 rotatedPerpAxis = rotation * perpAxis; - float roll = angleBetween(rotatedPerpAxis, perpAxis); + // measure the roll + // NOTE: perpAxis is perpendicular to both _coneAxis and rotatedConeAxis, so we can + // rotate it again and we'll end up with an something that has only been rolled. + glm::vec3 rolledPerpAxis = rotation * perpAxis; + float sign = glm::dot(rotatedAxis, glm::cross(perpAxis, rolledPerpAxis)) > 0.0f ? 1.0f : -1.0f; + float roll = sign * angleBetween(rolledPerpAxis, perpAxis); if (roll < _minRoll || roll > _maxRoll) { - float newRoll = clampAngle(roll, _minRoll, _maxRoll); - rotation = glm::angleAxis(newRoll - roll, rotatedAxis) * rotation; + float clampedRoll = clampAngle(roll, _minRoll, _maxRoll); + rotation = glm::angleAxis(clampedRoll - roll, rotatedAxis) * rotation; applied = true; } return applied; diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index 4c087821c5..22762ea524 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -284,8 +284,191 @@ void AngularConstraintTests::testHingeConstraint() { } void AngularConstraintTests::testConeRollerConstraint() { + float minAngleX = -PI / 5.0f; + float minAngleY = -PI / 5.0f; + float minAngleZ = -PI / 8.0f; + + float maxAngleX = PI / 4.0f; + float maxAngleY = PI / 3.0f; + float maxAngleZ = PI / 4.0f; + + glm::vec3 minAngles(minAngleX, minAngleY, minAngleZ); + glm::vec3 maxAngles(maxAngleX, maxAngleY, maxAngleZ); + AngularConstraint* c = AngularConstraint::newAngularConstraint(minAngles, maxAngles); + + float expectedConeAngle = 0.25 * (maxAngleX - minAngleX + maxAngleY - minAngleY); + glm::vec3 middleAngles = 0.5f * (maxAngles + minAngles); + glm::quat yaw = glm::angleAxis(middleAngles[1], glm::vec3(0.0f, 1.0f, 0.0f)); + glm::quat pitch = glm::angleAxis(middleAngles[0], glm::vec3(1.0f, 0.0f, 0.0f)); + glm::vec3 expectedConeAxis = pitch * yaw * glm::vec3(0.0f, 0.0f, 1.0f); + + glm::vec3 xAxis(1.0f, 0.0f, 0.0f); + glm::vec3 perpAxis = glm::normalize(xAxis - glm::dot(xAxis, expectedConeAxis) * expectedConeAxis); + + if (!c) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: newAngularConstraint() should make a constraint" << std::endl; + } + { // test in middle of constraint + glm::vec3 angles(PI/20.0f, 0.0f, PI/10.0f); + glm::quat rotation(angles); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not change rotation" << std::endl; + } + } + float deltaAngle = 0.001f; + { // test just inside edge of cone + glm::quat rotation = glm::angleAxis(expectedConeAngle - deltaAngle, perpAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not change rotation" << std::endl; + } + } + { // test just outside edge of cone + glm::quat rotation = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + } + { // test just inside min edge of roll + glm::quat rotation = glm::angleAxis(minAngleZ + deltaAngle, expectedConeAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not change rotation" << std::endl; + } + } + { // test just inside max edge of roll + glm::quat rotation = glm::angleAxis(maxAngleZ - deltaAngle, expectedConeAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not change rotation" << std::endl; + } + } + { // test just outside min edge of roll + glm::quat rotation = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngleZ, expectedConeAxis); + if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test just outside max edge of roll + glm::quat rotation = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngleZ, expectedConeAxis); + if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + deltaAngle = 0.25f * expectedConeAngle; + { // test far outside cone and min roll + glm::quat roll = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis); + glm::quat pitchYaw = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis); + glm::quat rotation = pitchYaw * roll; + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + glm::quat expectedRoll = glm::angleAxis(minAngleZ, expectedConeAxis); + glm::quat expectedPitchYaw = glm::angleAxis(expectedConeAngle, perpAxis); + glm::quat expectedRotation = expectedPitchYaw * expectedRoll; + if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test far outside cone and max roll + glm::quat roll = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis); + glm::quat pitchYaw = glm::angleAxis(- expectedConeAngle - deltaAngle, perpAxis); + glm::quat rotation = pitchYaw * roll; + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + glm::quat expectedRoll = glm::angleAxis(maxAngleZ, expectedConeAxis); + glm::quat expectedPitchYaw = glm::angleAxis(- expectedConeAngle, perpAxis); + glm::quat expectedRotation = expectedPitchYaw * expectedRoll; + if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } } void AngularConstraintTests::runAllTests() { testHingeConstraint(); + testConeRollerConstraint(); } diff --git a/tests/shared/src/main.cpp b/tests/shared/src/main.cpp index 3ae1b7b34d..6215d394a8 100644 --- a/tests/shared/src/main.cpp +++ b/tests/shared/src/main.cpp @@ -8,9 +8,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AngularConstraintTests.h" #include "MovingPercentileTests.h" int main(int argc, char** argv) { MovingPercentileTests::runAllTests(); + AngularConstraintTests::runAllTests(); return 0; } From bc1660cdeb20e4114445b5dfe28ff9d6f0f4aa4a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 1 Jul 2014 09:57:23 -0700 Subject: [PATCH 03/18] Configure multi-processor building on Windows --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7fa55d4a2..2451ab240a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ add_definitions(-DGLM_FORCE_RADIANS) if (WIN32) add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS) set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1 ") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic") #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas") From 1a1050cb06b360e1f201027dc60a5d199762b79c Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Tue, 1 Jul 2014 12:31:48 -0700 Subject: [PATCH 04/18] Added back _raiseMirror usage for mirror mode. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7fb3ded0d8..f21fedabea 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -592,7 +592,7 @@ void Application::paintGL() { _myCamera.setTightness(0.0f); _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); + _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); } // Update camera position From af30dc27223dd9e0a240890c95e1d65f822834be Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Tue, 1 Jul 2014 12:33:54 -0700 Subject: [PATCH 05/18] Updated oculus readme.txt for windows users --- interface/external/oculus/readme.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/external/oculus/readme.txt b/interface/external/oculus/readme.txt index f689f81478..f68818d1ee 100644 --- a/interface/external/oculus/readme.txt +++ b/interface/external/oculus/readme.txt @@ -10,4 +10,7 @@ You can download the Oculus SDK from https://developer.oculusvr.com/ (account cr You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects). If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'oculus' that contains the three folders mentioned above. -2. Clear your build directory, run cmake and build, and you should be all set. \ No newline at end of file + NOTE: For Windows users, you should copy libovr.lib and libovrd.lib from the \oculus\Lib\Win32\VS2010 directory to the \oculus\Lib\Win32\ directory. + +2. Clear your build directory, run cmake and build, and you should be all set. + From 67ecde7d312b3652130ef536924bd1616e8df7b1 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Tue, 1 Jul 2014 21:39:19 -0700 Subject: [PATCH 06/18] Made tree editor voxel world stationary and not crash --- interface/src/Application.cpp | 7 +-- interface/src/devices/OculusManager.cpp | 2 +- interface/src/devices/TV3DManager.cpp | 36 ++++++++++++ interface/src/ui/ApplicationOverlay.cpp | 75 ++++++++++++++++++++++++- interface/src/ui/ApplicationOverlay.h | 1 + 5 files changed, 113 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f21fedabea..b48d35c5e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -641,13 +641,8 @@ void Application::paintGL() { } } else if (TV3DManager::isConnected()) { - if (glowEnabled) { - _glowEffect.prepare(); - } + TV3DManager::display(whichCamera); - if (glowEnabled) { - _glowEffect.render(); - } } else { if (glowEnabled) { diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index d9549438b5..e156e148ab 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -262,7 +262,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); - // We only need to render the overlays to a texture once, then we just render the texture as a quad + // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() applicationOverlay.renderOverlay(true); const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::DisplayOculusOverlays); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index b5cc28b07f..98fe3ac6d4 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -93,6 +93,18 @@ void TV3DManager::display(Camera& whichCamera) { int portalW = Application::getInstance()->getGLWidget()->width() / 2; int portalH = Application::getInstance()->getGLWidget()->height(); + const bool glowEnabled = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect); + + ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); + + // We only need to render the overlays to a texture once, then we just render the texture as a quad + // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() + applicationOverlay.renderOverlay(true); + + if (glowEnabled) { + Application::getInstance()->getGlowEffect()->prepare(); + } + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); @@ -102,13 +114,24 @@ void TV3DManager::display(Camera& whichCamera) { glPushMatrix(); { + glMatrixMode(GL_PROJECTION); glLoadIdentity(); // reset projection matrix glFrustum(_leftEye.left, _leftEye.right, _leftEye.bottom, _leftEye.top, nearZ, farZ); // set left view frustum + GLfloat p[4][4]; + glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0])); + GLfloat cotangent = p[1][1]; + GLfloat fov = atan(1.0f / cotangent); glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax + + + printf("FOV %f\n", fov); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); + + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); } glPopMatrix(); glDisable(GL_SCISSOR_TEST); @@ -124,14 +147,27 @@ void TV3DManager::display(Camera& whichCamera) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); // reset projection matrix glFrustum(_rightEye.left, _rightEye.right, _rightEye.bottom, _rightEye.top, nearZ, farZ); // set left view frustum + GLfloat p[4][4]; + glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0])); + GLfloat cotangent = p[1][1]; + GLfloat fov = atan(1.0f / cotangent); glTranslatef(_rightEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax + + printf("FOV %f\n", fov); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); + + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); } glPopMatrix(); glDisable(GL_SCISSOR_TEST); // reset the viewport to how we started glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); + + if (glowEnabled) { + Application::getInstance()->getGlowEffect()->render(); + } } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 77e8986297..07582e2781 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -206,7 +206,7 @@ void ApplicationOverlay::getClickLocation(int &x, int &y) const { } } -// Draws the FBO texture for Oculus rift. TODO: Draw a curved texture instead of plane. +// Draws the FBO texture for Oculus rift. void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_alpha == 0.0f) { @@ -293,6 +293,79 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { } +// Draws the FBO texture for 3DTV. +void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) { + + if (_alpha == 0.0f) { + return; + } + + Application* application = Application::getInstance(); + + MyAvatar* myAvatar = application->getAvatar(); + const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); + + glActiveTexture(GL_TEXTURE0); + + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glLoadIdentity(); + // Transform to world space + glm::quat rotation = whichCamera.getRotation(); + glm::vec3 axis2 = glm::axis(rotation); + glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); + glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); + + // Translate to the front of the camera + glm::vec3 pos = whichCamera.getPosition(); + glm::quat rot = myAvatar->getOrientation(); + glm::vec3 axis = glm::axis(rot); + + glTranslatef(pos.x, pos.y, pos.z); + glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); + + glColor4f(1.0f, 1.0f, 1.0f, _alpha); + + //Render + const GLfloat distance = 1.0f; + + const GLfloat halfQuadHeight = atan(fov) * distance; + const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; + const GLfloat quadWidth = halfQuadWidth * 2.0f; + const GLfloat quadHeight = halfQuadHeight * 2.0f; + + const GLfloat x = -halfQuadWidth; + const GLfloat y = -halfQuadHeight; + + glBegin(GL_QUADS); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + quadHeight, -distance); + glTexCoord2f(1.0f, 1.0f); glVertex3f(x + quadWidth, y + quadHeight, -distance); + glTexCoord2f(1.0f, 0.0f); glVertex3f(x + quadWidth, y, -distance); + glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, -distance); + + glEnd(); + + glPopMatrix(); + + glDepthMask(GL_TRUE); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glEnable(GL_LIGHTING); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +} + //Renders optional pointers void ApplicationOverlay::renderPointers() { Application* application = Application::getInstance(); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index b9f9596ccf..7c1f87d575 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -29,6 +29,7 @@ public: void renderOverlay(bool renderToTexture = false); void displayOverlayTexture(); void displayOverlayTextureOculus(Camera& whichCamera); + void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov); void computeOculusPickRay(float x, float y, glm::vec3& direction) const; void getClickLocation(int &x, int &y) const; From c3f7d9d15598e2988270f27fbacaf21143968bae Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 2 Jul 2014 11:20:14 -0700 Subject: [PATCH 07/18] delete AngularConstraints at end of tests --- tests/shared/src/AngularConstraintTests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index 22762ea524..d6a9214acc 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -281,6 +281,7 @@ void AngularConstraintTests::testHingeConstraint() { << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; } } + delete c; } void AngularConstraintTests::testConeRollerConstraint() { @@ -466,6 +467,7 @@ void AngularConstraintTests::testConeRollerConstraint() { << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; } } + delete c; } void AngularConstraintTests::runAllTests() { From b018c1c4a554d5cef2d2ca5698daae344e903b88 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 2 Jul 2014 11:22:07 -0700 Subject: [PATCH 08/18] Add copy ctor for JointState create AngularConstraint for joints that need them (but not used yet) --- interface/src/renderer/JointState.cpp | 30 ++++++++++++++++++++++++--- interface/src/renderer/JointState.h | 4 +++- interface/src/renderer/Model.cpp | 3 +-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/interface/src/renderer/JointState.cpp b/interface/src/renderer/JointState.cpp index 3b3c135eb5..f7b4dbc96f 100644 --- a/interface/src/renderer/JointState.cpp +++ b/interface/src/renderer/JointState.cpp @@ -23,6 +23,15 @@ JointState::JointState() : _constraint(NULL) { } +JointState::JointState(const JointState& other) : _constraint(NULL) { + _rotationInParentFrame = other._rotationInParentFrame; + _transform = other._transform; + _rotation = other._rotation; + _animationPriority = other._animationPriority; + _fbxJoint = other._fbxJoint; + // DO NOT copy _constraint +} + JointState::~JointState() { delete _constraint; _constraint = NULL; @@ -33,6 +42,22 @@ void JointState::setFBXJoint(const FBXJoint* joint) { _rotationInParentFrame = joint->rotation; // NOTE: JointState does not own the FBXJoint to which it points. _fbxJoint = joint; + if (_constraint) { + delete _constraint; + _constraint = NULL; + } +} + +void JointState::updateConstraint() { + if (_constraint) { + delete _constraint; + _constraint = NULL; + } + if (glm::distance2(glm::vec3(-PI), _fbxJoint->rotationMin) > EPSILON || + glm::distance2(glm::vec3(PI), _fbxJoint->rotationMax) > EPSILON ) { + // this joint has rotation constraints + _constraint = AngularConstraint::newAngularConstraint(_fbxJoint->rotationMin, _fbxJoint->rotationMax); + } } void JointState::copyState(const JointState& state) { @@ -40,7 +65,7 @@ void JointState::copyState(const JointState& state) { _transform = state._transform; _rotation = extractRotation(_transform); _animationPriority = state._animationPriority; - // DO NOT copy _fbxJoint + // DO NOT copy _fbxJoint or _constraint } void JointState::computeTransform(const glm::mat4& parentTransform) { @@ -88,8 +113,7 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa return; } _animationPriority = priority; - if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) && - _fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) { + if (!constrain || _constraint == NULL) { // no constraints _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation; _rotation = delta * _rotation; diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h index 4eadc51f7c..e5f02fdf16 100644 --- a/interface/src/renderer/JointState.h +++ b/interface/src/renderer/JointState.h @@ -23,11 +23,13 @@ class AngularConstraint; class JointState { public: JointState(); + JointState(const JointState& other); ~JointState(); void setFBXJoint(const FBXJoint* joint); const FBXJoint& getFBXJoint() const { return *_fbxJoint; } + void updateConstraint(); void copyState(const JointState& state); void computeTransform(const glm::mat4& parentTransform); @@ -64,7 +66,7 @@ private: glm::quat _rotation; // joint- to model-frame const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint - AngularConstraint* _constraint; + AngularConstraint* _constraint; // JointState owns its AngularConstraint }; #endif // hifi_JointState_h diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3b5cda4fd2..a86d392981 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -561,8 +561,6 @@ bool Model::updateGeometry() { void Model::setJointStates(QVector states) { _jointStates = states; - // compute an approximate bounding radius for broadphase collision queries - // against PhysicsSimulation boundaries int numJoints = _jointStates.size(); float radius = 0.0f; for (int i = 0; i < numJoints; ++i) { @@ -570,6 +568,7 @@ void Model::setJointStates(QVector states) { if (distance > radius) { radius = distance; } + _jointStates[i].updateConstraint(); } _boundingRadius = radius; } From e903b1659a1f79ea2c8ab23644353d198134947d Mon Sep 17 00:00:00 2001 From: Chris Oates Date: Wed, 2 Jul 2014 13:09:16 -0700 Subject: [PATCH 09/18] Implemented Improved Perlin Noise in existing "textured voxels" option. TextureCache.cpp: modified so that permutation texture contains known permutation of 0..255 rather than random set of values. Does not noticeably affect visuals. perlin_modulate.frag: implementation of improved noise, per 2002 SIGGRAPH paper, including "turbulence" summation. --- .../resources/shaders/perlin_modulate.frag | 109 ++++++++++++++++-- interface/src/renderer/TextureCache.cpp | 37 +++++- 2 files changed, 136 insertions(+), 10 deletions(-) diff --git a/interface/resources/shaders/perlin_modulate.frag b/interface/resources/shaders/perlin_modulate.frag index 8693b14e1b..23d31ff72e 100644 --- a/interface/resources/shaders/perlin_modulate.frag +++ b/interface/resources/shaders/perlin_modulate.frag @@ -11,18 +11,114 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// the texture containing our permutations and normals -uniform sampler2D permutationNormalTexture; +// implementation based on Ken Perlin's Improved Noise reference implementation (orig. in Java) at +// http://mrl.nyu.edu/~perlin/noise/ + +uniform sampler2D permutationTexture; // the noise frequency -const float frequency = 65536.0; // looks better with current TREE_SCALE, was 1024 when TREE_SCALE was either 512 or 128 +const float frequency = 256.0; +//const float frequency = 65536.0; // looks better with current TREE_SCALE, was 1024 when TREE_SCALE was either 512 or 128 // the noise amplitude -const float amplitude = 0.1; +const float amplitude = 0.5; // the position in model space varying vec3 position; +// gradient based on gradients from cube edge centers rather than random from texture lookup +float randomEdgeGrad(int hash, vec3 position){ + int h = int(mod(hash, 16)); + float u = h < 8 ? position.x : position.y; + float v = h < 4 ? position.y : h == 12 || h == 14 ? position.x : position.z; + bool even = mod(hash, 2) == 0; + bool four = mod(hash, 4) == 0; + return (even ? u : -u) + (four ? v : -v); +} + +// still have the option to lookup based on texture +float randomTextureGrad(int hash, vec3 position){ + float u = float(hash) / 256.0; + vec3 g = -1 + 2 * texture2D(permutationTexture, vec2(u, 0.75)).rgb; + return dot(position, g); +} + +float improvedGrad(int hash, vec3 position){ +// Untested whether texture lookup is faster than math, uncomment one line or the other to try out +// cube edge gradients versus random spherical gradients sent in texture. + +// return randomTextureGrad(hash, position); + return randomEdgeGrad(hash, position); +} + +// 5th order fade function to remove 2nd order discontinuties +vec3 fade3(vec3 t){ + return t * t * t * (t * (t * 6 - 15) + 10); +} + +int permutation(int index){ + float u = float(index) / 256.0; + float t = texture2D(permutationTexture, vec2(u, 0.25)).r; + return int(t * 256); +} + +float improvedNoise(vec3 position){ + int X = int(mod(floor(position.x), 256)); + int Y = int(mod(floor(position.y), 256)); + int Z = int(mod(floor(position.z), 256)); + + vec3 fracs = fract(position); + + vec3 fades = fade3(fracs); + + int A = permutation(X + 0) + Y; + int AA = permutation(A + 0) + Z; + int AB = permutation(A + 1) + Z; + int B = permutation(X + 1) + Y; + int BA = permutation(B + 0) + Z; + int BB = permutation(B + 1) + Z; + + float gradAA0 = improvedGrad(permutation(AA + 0), vec3(fracs.x , fracs.y , fracs.z )); + float gradBA0 = improvedGrad(permutation(BA + 0), vec3(fracs.x - 1, fracs.y , fracs.z )); + float gradAB0 = improvedGrad(permutation(AB + 0), vec3(fracs.x , fracs.y - 1, fracs.z )); + float gradBB0 = improvedGrad(permutation(BB + 0), vec3(fracs.x - 1, fracs.y - 1, fracs.z )); + float gradAA1 = improvedGrad(permutation(AA + 1), vec3(fracs.x , fracs.y , fracs.z - 1)); + float gradBA1 = improvedGrad(permutation(BA + 1), vec3(fracs.x - 1, fracs.y , fracs.z - 1)); + float gradAB1 = improvedGrad(permutation(AB + 1), vec3(fracs.x , fracs.y - 1, fracs.z - 1)); + float gradBB1 = improvedGrad(permutation(BB + 1), vec3(fracs.x - 1, fracs.y - 1, fracs.z - 1)); + + return mix(mix(mix(gradAA0, gradBA0, fades.x), mix(gradAB0, gradBB0, fades.x), fades.y), mix(mix(gradAA1, gradBA1, fades.x), mix(gradAB1, gradBB1, fades.x), fades.y), fades.z); +} + +float turbulence(vec3 position, float power){ + return (1.0f / power) * improvedNoise(power * position); +} + +float turb(vec3 position){ + return turbulence(position, 1) + + turbulence(position, 2), + + turbulence(position, 4) + + turbulence(position, 8) + + turbulence(position, 16) + + turbulence(position, 32) + + turbulence(position, 64) + + turbulence(position, 128) + ; +} + + +void main(void) { + + // get noise in range 0 .. 1 + float noise = clamp(0.5f + amplitude * turb(position * frequency), 0, 1); + + // apply vertex lighting + vec3 color = gl_Color.rgb * vec3(noise, noise, noise); + gl_FragColor = vec4(color, 1); +} + + +/* old implementation // returns the gradient at a single corner of our sampling cube vec3 grad(vec3 location) { float p1 = texture2D(permutationNormalTexture, vec2(location.x / 256.0, 0.25)).r; @@ -60,7 +156,4 @@ float perlin(vec3 location) { mix(mix(ffcv, cfcv, params.x), mix(fccv, cccv, params.x), params.y), params.z); } - -void main(void) { - gl_FragColor = vec4(gl_Color.rgb * (1.0 + amplitude*(perlin(position * frequency) - 1.0)), 1.0); -} +*/ \ No newline at end of file diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 0588ca70d2..c792cc59a9 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -51,6 +51,33 @@ TextureCache::~TextureCache() { delete _tertiaryFramebufferObject; } +// use fixed table of permutations. Could also make ordered list programmatically +// and then shuffle algorithm. For testing, this ensures consistent behavior in each run. +// this list taken from Ken Perlin's Improved Noise reference implementation (orig. in Java) at +// http://mrl.nyu.edu/~perlin/noise/ + +const int permutation[256] = +{ + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, + 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, + 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, + 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, + 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, + 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, + 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, + 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, + 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, + 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, + 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, + 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, + 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, + 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 +}; + +#define USE_CHRIS_NOISE 0 + GLuint TextureCache::getPermutationNormalTextureID() { if (_permutationNormalTextureID == 0) { glGenTextures(1, &_permutationNormalTextureID); @@ -58,10 +85,17 @@ GLuint TextureCache::getPermutationNormalTextureID() { // the first line consists of random permutation offsets unsigned char data[256 * 2 * 3]; +#if defined(USE_CHRIS_NOISE) + for (int i = 0; i < 256; i++) { + data[3*i+0] = permutation[i]; + data[3*i+1] = permutation[i]; + data[3*i+2] = permutation[i]; +#else for (int i = 0; i < 256 * 3; i++) { data[i] = rand() % 256; +#endif } - // the next, random unit normals + for (int i = 256 * 3; i < 256 * 3 * 2; i += 3) { glm::vec3 randvec = glm::sphericalRand(1.0f); data[i] = ((randvec.x + 1.0f) / 2.0f) * 255.0f; @@ -71,7 +105,6 @@ GLuint TextureCache::getPermutationNormalTextureID() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); } return _permutationNormalTextureID; From c79c5df295111060468b6fe991b0be18f0fc5889 Mon Sep 17 00:00:00 2001 From: Chris Oates Date: Wed, 2 Jul 2014 13:50:47 -0700 Subject: [PATCH 10/18] Fixing up #define / #if pair so that permutation table change can be turned of by setting #defined variable to 0 instead of having to comment it out. --- interface/src/renderer/TextureCache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 1352b2c326..01c3dc1cc1 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -110,7 +110,7 @@ const int permutation[256] = 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; -#define USE_CHRIS_NOISE 0 +#define USE_CHRIS_NOISE 1 GLuint TextureCache::getPermutationNormalTextureID() { if (_permutationNormalTextureID == 0) { @@ -119,7 +119,7 @@ GLuint TextureCache::getPermutationNormalTextureID() { // the first line consists of random permutation offsets unsigned char data[256 * 2 * 3]; -#if defined(USE_CHRIS_NOISE) +#if (USE_CHRIS_NOISE==1) for (int i = 0; i < 256; i++) { data[3*i+0] = permutation[i]; data[3*i+1] = permutation[i]; From 90a27bb118dd82e31d2989089e93be9cd746b77d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 15:18:56 -0700 Subject: [PATCH 11/18] Removed json callback --- libraries/networking/src/UserActivityLogger.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index aa18cb43ee..5b20c82263 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -83,17 +83,10 @@ void UserActivityLogger::close(int delayTime) { // In order to get the end of the session, we need to give the account manager enough time to send the packet. QEventLoop loop; - // Here we connect the callbacks to stop the event loop - JSONCallbackParameters params; - params.jsonCallbackReceiver = &loop; - params.errorCallbackReceiver = &loop; - params.jsonCallbackMethod = "quit"; - params.errorCallbackMethod = "quit"; - // In case something goes wrong, we also setup a timer so that the delai is not greater than delayTime QTimer timer; connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); // Now we can log it - logAction(ACTION_NAME, QJsonObject(), params); + logAction(ACTION_NAME, QJsonObject()); timer.start(delayTime); loop.exec(); } From 45db5e2c40b610b86a100aa6c9ea82d8b539a5b0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 15:57:11 -0700 Subject: [PATCH 12/18] Removed Xcode warnings --- interface/src/ScriptsModel.cpp | 2 -- libraries/particles/src/ParticleCollisionSystem.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/interface/src/ScriptsModel.cpp b/interface/src/ScriptsModel.cpp index f9ed94f3fa..7e57d2971e 100644 --- a/interface/src/ScriptsModel.cpp +++ b/interface/src/ScriptsModel.cpp @@ -30,8 +30,6 @@ static const QString IS_TRUNCATED_NAME = "IsTruncated"; static const QString CONTAINER_NAME = "Contents"; static const QString KEY_NAME = "Key"; -static const int SCRIPT_PATH = Qt::UserRole; - ScriptItem::ScriptItem(const QString& filename, const QString& fullPath) : _filename(filename), _fullPath(fullPath) { diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index d8d5887d97..0291690c3d 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -183,7 +183,6 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) // MIN_VALID_SPEED is obtained by computing speed gained at one gravity after the shortest expected frame const float MIN_EXPECTED_FRAME_PERIOD = 0.0167f; // 1/60th of a second -const float HALTING_SPEED = 9.8 * MIN_EXPECTED_FRAME_PERIOD / (float)(TREE_SCALE); void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { // particles that are in hand, don't collide with avatars From a859094d4a6e930aa718ababb89c556c6da80394 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 2 Jul 2014 16:40:02 -0700 Subject: [PATCH 13/18] Clickable 3D UI in 3DTV --- interface/src/Application.cpp | 2 +- interface/src/devices/TV3DManager.cpp | 5 ---- interface/src/ui/ApplicationOverlay.cpp | 34 ++++++++++++++++++++++--- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b48d35c5e8..b24c3ac949 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1130,7 +1130,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { _lastMouseMove = usecTimestampNow(); - if (_mouseHidden && showMouse && !OculusManager::isConnected()) { + if (_mouseHidden && showMouse && !OculusManager::isConnected() && !TV3DManager::isConnected()) { getGLWidget()->setCursor(Qt::ArrowCursor); _mouseHidden = false; _seenMouseMove = true; diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index 98fe3ac6d4..25d3ff892a 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -124,9 +124,6 @@ void TV3DManager::display(Camera& whichCamera) { GLfloat fov = atan(1.0f / cotangent); glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax - - printf("FOV %f\n", fov); - glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); @@ -153,8 +150,6 @@ void TV3DManager::display(Camera& whichCamera) { GLfloat fov = atan(1.0f / cotangent); glTranslatef(_rightEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax - printf("FOV %f\n", fov); - glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 07582e2781..44a83e164a 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -335,15 +335,17 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as glColor4f(1.0f, 1.0f, 1.0f, _alpha); //Render + // fov -= RADIANS_PER_DEGREE * 2.5f; //reduce by 5 degrees so it fits in the view const GLfloat distance = 1.0f; - const GLfloat halfQuadHeight = atan(fov) * distance; + const GLfloat halfQuadHeight = distance * tan(fov); const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; const GLfloat quadWidth = halfQuadWidth * 2.0f; const GLfloat quadHeight = halfQuadHeight * 2.0f; - const GLfloat x = -halfQuadWidth; - const GLfloat y = -halfQuadHeight; + GLfloat x = -halfQuadWidth; + GLfloat y = -halfQuadHeight; + glDisable(GL_DEPTH_TEST); glBegin(GL_QUADS); @@ -354,6 +356,32 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as glEnd(); + if (_crosshairTexture == 0) { + _crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png")); + } + + //draw the mouse pointer + glBindTexture(GL_TEXTURE_2D, _crosshairTexture); + + const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth; + x -= reticleSize / 2.0f; + y += reticleSize / 2.0f; + const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->width()) * quadWidth; + const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->height())) * quadHeight; + + glBegin(GL_QUADS); + + glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]); + + glTexCoord2d(0.0f, 0.0f); glVertex3f(x + mouseX, y + mouseY, -distance); + glTexCoord2d(1.0f, 0.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY, -distance); + glTexCoord2d(1.0f, 1.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance); + glTexCoord2d(0.0f, 1.0f); glVertex3f(x + mouseX, y + mouseY - reticleSize, -distance); + + glEnd(); + + glEnable(GL_DEPTH_TEST); + glPopMatrix(); glDepthMask(GL_TRUE); From ee30a446e9f21a84cf27ab2008d09cb84f9c123c Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 2 Jul 2014 16:45:05 -0700 Subject: [PATCH 14/18] Fixed 3rd person camera for non oculus --- interface/src/Application.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b24c3ac949..ab6d1d1e20 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -586,7 +586,11 @@ void Application::paintGL() { //Note, the camera distance is set in Camera::setMode() so we dont have to do it here. _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition()); - _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation()); + if (OculusManager::isConnected()) { + _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation()); + } else { + _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation()); + } } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness(0.0f); From edcf4d04f8f0396c119ca2668969f9c334f47ab7 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 2 Jul 2014 17:05:06 -0700 Subject: [PATCH 15/18] Fixed bug when switching from normal view to oculus --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ab6d1d1e20..7cfadc1ff2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -634,6 +634,10 @@ void Application::paintGL() { //If we aren't using the glow shader, we have to clear the color and depth buffer if (!glowEnabled) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } else if (OculusManager::isConnected()) { + //Clear the color buffer to ensure that there isnt any residual color + //Left over from when OR was not connected. + glClear(GL_COLOR_BUFFER_BIT); } if (OculusManager::isConnected()) { From 69533c25c2f3d10098566424cbac1e97ae58e88d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 17:54:21 -0700 Subject: [PATCH 16/18] Fix script not being loaded at startup --- interface/src/Application.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0f8fbbae56..6c1982f328 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -398,18 +398,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : } Application::~Application() { + qInstallMessageHandler(NULL); + + saveSettings(); + storeSizeAndPosition(); + saveScripts(); + int DELAY_TIME = 1000; UserActivityLogger::getInstance().close(DELAY_TIME); - qInstallMessageHandler(NULL); - // make sure we don't call the idle timer any more delete idleTimer; - + _sharedVoxelSystem.changeTree(new VoxelTree); - - saveSettings(); - delete _voxelImporter; // let the avatar mixer know we're out @@ -432,8 +433,6 @@ Application::~Application() { _particleEditSender.terminate(); _modelEditSender.terminate(); - storeSizeAndPosition(); - saveScripts(); VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown Menu::getInstance()->deleteLater(); From 356a29c2fbb82f2a3080e4b71f7e66f177ff9536 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 3 Jul 2014 08:40:34 -0700 Subject: [PATCH 17/18] add AngularConstraint::softClamp() for hands --- interface/src/renderer/JointState.cpp | 13 +++- interface/src/renderer/JointState.h | 2 +- interface/src/renderer/Model.cpp | 2 +- libraries/shared/src/AngularConstraint.cpp | 34 +++++++-- libraries/shared/src/AngularConstraint.h | 8 +- tests/shared/src/AngularConstraintTests.cpp | 84 ++++++++++----------- 6 files changed, 88 insertions(+), 55 deletions(-) diff --git a/interface/src/renderer/JointState.cpp b/interface/src/renderer/JointState.cpp index 6cb58f0664..429084480d 100644 --- a/interface/src/renderer/JointState.cpp +++ b/interface/src/renderer/JointState.cpp @@ -24,9 +24,9 @@ JointState::JointState() : } JointState::JointState(const JointState& other) : _constraint(NULL) { - _rotationInParentFrame = other._rotationInParentFrame; _transform = other._transform; _rotation = other._rotation; + _rotationInParentFrame = other._rotationInParentFrame; _animationPriority = other._animationPriority; _fbxJoint = other._fbxJoint; // DO NOT copy _constraint @@ -102,11 +102,15 @@ void JointState::restoreRotation(float fraction, float priority) { } } -void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) { +void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority, bool constrain) { // rotation is from bind- to model-frame assert(_fbxJoint != NULL); if (priority >= _animationPriority) { - setRotationInParentFrame(_rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation)); + glm::quat targetRotation = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); + if (constrain && _constraint) { + _constraint->softClamp(targetRotation, _rotationInParentFrame, 0.5f); + } + setRotationInParentFrame(targetRotation); _animationPriority = priority; } } @@ -154,6 +158,9 @@ void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float if (mixFactor > 0.0f && mixFactor <= 1.0f) { targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor); } + if (_constraint) { + _constraint->softClamp(targetRotation, _rotationInParentFrame, 0.5f); + } setRotationInParentFrame(targetRotation); } diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h index 5e8c8704fc..3bd752cdff 100644 --- a/interface/src/renderer/JointState.h +++ b/interface/src/renderer/JointState.h @@ -68,7 +68,7 @@ public: /// \param rotation is from bind- to model-frame /// computes and sets new _rotationInParentFrame /// NOTE: the JointState's model-frame transform/rotation are NOT updated! - void setRotationFromBindFrame(const glm::quat& rotation, float priority); + void setRotationFromBindFrame(const glm::quat& rotation, float priority, bool constrain = false); void setRotationInParentFrame(const glm::quat& targetRotation); const glm::quat& getRotationInParentFrame() const { return _rotationInParentFrame; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c47fd0893f..1d822c7ed1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1216,7 +1216,7 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: } while (numIterations < MAX_ITERATION_COUNT && distanceToGo < ACCEPTABLE_IK_ERROR); // set final rotation of the end joint - endState.setRotationFromBindFrame(targetRotation, priority); + endState.setRotationFromBindFrame(targetRotation, priority, true); _shapesAreDirty = !_shapes.isEmpty(); } diff --git a/libraries/shared/src/AngularConstraint.cpp b/libraries/shared/src/AngularConstraint.cpp index 48649450e1..4689568ac8 100644 --- a/libraries/shared/src/AngularConstraint.cpp +++ b/libraries/shared/src/AngularConstraint.cpp @@ -74,6 +74,26 @@ AngularConstraint* AngularConstraint::newAngularConstraint(const glm::vec3& minA return NULL; } +bool AngularConstraint::softClamp(glm::quat& targetRotation, const glm::quat& oldRotation, float mixFraction) { + glm::quat clampedTarget = targetRotation; + bool clamped = clamp(clampedTarget); + if (clamped) { + // check if oldRotation is also clamped + glm::quat clampedOld = oldRotation; + bool clamped2 = clamp(clampedOld); + if (clamped2) { + // oldRotation is already beyond the constraint + // we clamp again midway between targetRotation and clamped oldPosition + clampedTarget = glm::shortMix(clampedOld, targetRotation, mixFraction); + // and then clamp that + clamp(clampedTarget); + } + // finally we mix targetRotation with the clampedTarget + targetRotation = glm::shortMix(clampedTarget, targetRotation, mixFraction); + } + return clamped; +} + HingeConstraint::HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& rotationAxis, float minAngle, float maxAngle) : _minAngle(minAngle), _maxAngle(maxAngle) { assert(_minAngle < _maxAngle); @@ -87,7 +107,7 @@ HingeConstraint::HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& } // virtual -bool HingeConstraint::applyTo(glm::quat& rotation) const { +bool HingeConstraint::clamp(glm::quat& rotation) const { glm::vec3 forward = rotation * _forwardAxis; forward -= glm::dot(forward, _rotationAxis) * _rotationAxis; float length = glm::length(forward); @@ -108,6 +128,11 @@ bool HingeConstraint::applyTo(glm::quat& rotation) const { return false; } +bool HingeConstraint::softClamp(glm::quat& targetRotation, const glm::quat& oldRotation, float mixFraction) { + // the hinge works best without a soft clamp + return clamp(targetRotation); +} + ConeRollerConstraint::ConeRollerConstraint(float coneAngle, const glm::vec3& coneAxis, float minRoll, float maxRoll) : _coneAngle(coneAngle), _minRoll(minRoll), _maxRoll(maxRoll) { assert(_maxRoll >= _minRoll); @@ -117,7 +142,7 @@ ConeRollerConstraint::ConeRollerConstraint(float coneAngle, const glm::vec3& con } // virtual -bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { +bool ConeRollerConstraint::clamp(glm::quat& rotation) const { bool applied = false; glm::vec3 rotatedAxis = rotation * _coneAxis; glm::vec3 perpAxis = glm::cross(rotatedAxis, _coneAxis); @@ -131,8 +156,7 @@ bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { rotatedAxis = rotation * _coneAxis; applied = true; } - } - else { + } else { // the rotation is 100% roll // there is no obvious perp axis so we must pick one perpAxis = rotatedAxis; @@ -168,7 +192,7 @@ bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { float roll = sign * angleBetween(rolledPerpAxis, perpAxis); if (roll < _minRoll || roll > _maxRoll) { float clampedRoll = clampAngle(roll, _minRoll, _maxRoll); - rotation = glm::angleAxis(clampedRoll - roll, rotatedAxis) * rotation; + rotation = glm::normalize(glm::angleAxis(clampedRoll - roll, rotatedAxis) * rotation); applied = true; } return applied; diff --git a/libraries/shared/src/AngularConstraint.h b/libraries/shared/src/AngularConstraint.h index 8003e4c9a3..929a58959b 100644 --- a/libraries/shared/src/AngularConstraint.h +++ b/libraries/shared/src/AngularConstraint.h @@ -24,14 +24,16 @@ public: AngularConstraint() {} virtual ~AngularConstraint() {} - virtual bool applyTo(glm::quat& rotation) const = 0; + virtual bool clamp(glm::quat& rotation) const = 0; + virtual bool softClamp(glm::quat& targetRotation, const glm::quat& oldRotation, float mixFraction); protected: }; class HingeConstraint : public AngularConstraint { public: HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& rotationAxis, float minAngle, float maxAngle); - virtual bool applyTo(glm::quat& rotation) const; + virtual bool clamp(glm::quat& rotation) const; + virtual bool softClamp(glm::quat& targetRotation, const glm::quat& oldRotation, float mixFraction); protected: glm::vec3 _forwardAxis; glm::vec3 _rotationAxis; @@ -42,7 +44,7 @@ protected: class ConeRollerConstraint : public AngularConstraint { public: ConeRollerConstraint(float coneAngle, const glm::vec3& coneAxis, float minRoll, float maxRoll); - virtual bool applyTo(glm::quat& rotation) const; + virtual bool clamp(glm::quat& rotation) const; private: float _coneAngle; glm::vec3 _coneAxis; diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index d6a9214acc..00916a7267 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -36,10 +36,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should not applyTo()" << std::endl; + << " ERROR: HingeConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -51,10 +51,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should not applyTo()" << std::endl; + << " ERROR: HingeConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -66,10 +66,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should not applyTo()" << std::endl; + << " ERROR: HingeConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -81,10 +81,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -102,10 +102,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -123,10 +123,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -144,10 +144,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -169,10 +169,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -193,10 +193,10 @@ void AngularConstraintTests::testHingeConstraint() { rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -217,10 +217,10 @@ void AngularConstraintTests::testHingeConstraint() { rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -241,10 +241,10 @@ void AngularConstraintTests::testHingeConstraint() { rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -265,10 +265,10 @@ void AngularConstraintTests::testHingeConstraint() { rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -315,10 +315,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation(angles); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -330,10 +330,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(expectedConeAngle - deltaAngle, perpAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -344,10 +344,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -358,10 +358,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(minAngleZ + deltaAngle, expectedConeAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -372,10 +372,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(maxAngleZ - deltaAngle, expectedConeAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -386,10 +386,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -405,10 +405,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -427,10 +427,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = pitchYaw * roll; glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -450,10 +450,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = pitchYaw * roll; glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ From 55dd2a4835be6d86fa9a235eef920b246209baf5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 3 Jul 2014 09:10:23 -0700 Subject: [PATCH 18/18] re-enable gravity effect on arm IK --- interface/src/renderer/Model.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1d822c7ed1..86d742c949 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1158,14 +1158,9 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: } glm::quat deltaRotation = rotationBetween(leverArm, targetPosition - pivot); - /* DON'T REMOVE! This code provides the gravitational effect on the IK solution. - * It is commented out for the moment because we're blending the IK solution with - * the default pose which provides similar stability, but we might want to use - * gravity again later. - - // We want to mix the shortest rotation with one that will pull the system down with gravity. - // So we compute a simplified center of mass, where each joint has a mass of 1.0 and we don't - // bother averaging it because we only need direction. + // We want to mix the shortest rotation with one that will pull the system down with gravity + // so that limbs don't float unrealistically. To do this we compute a simplified center of mass + // where each joint has unit mass and we don't bother averaging it because we only need direction. if (j > 1) { glm::vec3 centerOfMass(0.0f); @@ -1187,11 +1182,9 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: } deltaRotation = safeMix(deltaRotation, gravityDelta, mixFactor); } - */ // Apply the rotation, but use mixRotationDelta() which blends a bit of the default pose - // at in the process. This provides stability to the IK solution and removes the necessity - // for the gravity effect. + // at in the process. This provides stability to the IK solution for most models. glm::quat oldNextRotation = nextState.getRotation(); float mixFactor = 0.03f; nextState.mixRotationDelta(deltaRotation, mixFactor, priority);