From 5d4ef8d5b8054fcf33a7dddc768f6518d33e499a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Mar 2015 14:30:26 -0800 Subject: [PATCH 01/43] initial flailing --- interface/src/avatar/Avatar.h | 2 +- interface/src/avatar/MyAvatar.cpp | 42 +++++++++++++++++++++-- interface/src/avatar/MyAvatar.h | 16 +++++++++ libraries/physics/src/PhysicsSimulation.h | 2 ++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 72b7ecf93a..9b166e866f 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -188,7 +188,7 @@ protected: // These position histories and derivatives are in the world-frame. // The derivatives are the MEASURED results of all external and internal forces - // and are therefor READ-ONLY --> motion control of the Avatar is NOT obtained + // and are therefore READ-ONLY --> motion control of the Avatar is NOT obtained // by setting these values. // Floating point error prevents us from accurately measuring velocity using a naive approach // (e.g. vel = (pos - lastPos)/dt) so instead we use _positionDeltaAccumulator. diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8c4ea73775..3ec53ca396 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -92,8 +92,7 @@ MyAvatar::MyAvatar() : _physicsSimulation(), _feetTouchFloor(true), _isLookingAtLeftEye(true), - _realWorldFieldOfView("realWorldFieldOfView", - DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES) + _realWorldFieldOfView("realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES) { ShapeCollider::initDispatchTable(); for (int i = 0; i < MAX_DRIVE_KEYS; i++) { @@ -107,6 +106,8 @@ MyAvatar::MyAvatar() : // connect to AddressManager signal for location jumps connect(DependencyManager::get().data(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation); + + setupAvatarCollision(); } MyAvatar::~MyAvatar() { @@ -1979,3 +1980,40 @@ void MyAvatar::clearDriveKeys() { _driveKeys[i] = 0.0f; } } + + +void MyAvatar::setupAvatarCollision() { + btTransform startTransform = btTransform (glmToBullet(getOrientation()), glmToBullet(getPosition())); + + class btPairCachingGhostObject* m_ghostObject = new btPairCachingGhostObject(); + m_ghostObject->setWorldTransform(startTransform); + + btScalar characterHeight = 1.75; + btScalar characterWidth = 1.75; + btScalar stepHeight = btScalar(0.35); + + btConvexShape* capsule = new btCapsuleShape(characterWidth, characterHeight); + m_ghostObject->setCollisionShape(capsule); + m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + + _characterController = new btKinematicCharacterController(m_ghostObject, capsule, stepHeight); + + // PhysicsSimulation _physicsSimulation + // PhysicsEngine --> ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; + + _dynamicsWorld->addCollisionObject(m_ghostObject, btBroadphaseProxy::CharacterFilter, + btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + _dynamicsWorld->addAction(_characterController); +} + + +void MyAvatar::setAvatarMotion() { + /* + float dt = getDeltaTimeMicroseconds() * 0.000001f; + btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); + btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s + btScalar walkSpeed = walkVelocity * dt; + + _characterController->setWalkDirection(walkDirection*walkSpeed); + */ +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index ae392268f0..9e425e2ec8 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -15,10 +15,21 @@ #include #include + +#include +#include +#include +#include +#include + + + #include "Avatar.h" class ModelItemID; + + class MyAvatar : public Avatar { Q_OBJECT Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally) @@ -241,6 +252,11 @@ private: void updateChatCircle(float deltaTime); void maybeUpdateBillboard(); void setGravity(const glm::vec3& gravity); + + /// character collisions + btCharacterControllerInterface* _characterController; + void setupAvatarCollision(); + void setAvatarMotion(); }; #endif // hifi_MyAvatar_h diff --git a/libraries/physics/src/PhysicsSimulation.h b/libraries/physics/src/PhysicsSimulation.h index 90d6e38187..404731e589 100644 --- a/libraries/physics/src/PhysicsSimulation.h +++ b/libraries/physics/src/PhysicsSimulation.h @@ -61,6 +61,8 @@ public: bool getShapeCollisions(const Shape* shape, CollisionList& collisions) const; + void setupAvatarCollision(); + protected: void integrate(float deltaTime); From 7e4b597ca32d8dee914139118818ca6b8e4a2423 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Mar 2015 15:45:10 -0800 Subject: [PATCH 02/43] keep physics specific code in PhysicsEngine --- interface/src/Application.cpp | 2 ++ interface/src/avatar/MyAvatar.cpp | 39 ---------------------- interface/src/avatar/MyAvatar.h | 14 -------- libraries/physics/src/PhysicsEngine.cpp | 43 +++++++++++++++++++++++++ libraries/physics/src/PhysicsEngine.h | 11 +++++++ 5 files changed, 56 insertions(+), 53 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe41621dc1..811af7403d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1766,6 +1766,8 @@ void Application::init() { tree->setSimulation(&_physicsEngine); _physicsEngine.init(&_entityEditSender); + _physicsEngine.setAvatarData(_myAvatar); + connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3ec53ca396..b5cd2c0bfe 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -106,8 +106,6 @@ MyAvatar::MyAvatar() : // connect to AddressManager signal for location jumps connect(DependencyManager::get().data(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation); - - setupAvatarCollision(); } MyAvatar::~MyAvatar() { @@ -1980,40 +1978,3 @@ void MyAvatar::clearDriveKeys() { _driveKeys[i] = 0.0f; } } - - -void MyAvatar::setupAvatarCollision() { - btTransform startTransform = btTransform (glmToBullet(getOrientation()), glmToBullet(getPosition())); - - class btPairCachingGhostObject* m_ghostObject = new btPairCachingGhostObject(); - m_ghostObject->setWorldTransform(startTransform); - - btScalar characterHeight = 1.75; - btScalar characterWidth = 1.75; - btScalar stepHeight = btScalar(0.35); - - btConvexShape* capsule = new btCapsuleShape(characterWidth, characterHeight); - m_ghostObject->setCollisionShape(capsule); - m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); - - _characterController = new btKinematicCharacterController(m_ghostObject, capsule, stepHeight); - - // PhysicsSimulation _physicsSimulation - // PhysicsEngine --> ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; - - _dynamicsWorld->addCollisionObject(m_ghostObject, btBroadphaseProxy::CharacterFilter, - btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); - _dynamicsWorld->addAction(_characterController); -} - - -void MyAvatar::setAvatarMotion() { - /* - float dt = getDeltaTimeMicroseconds() * 0.000001f; - btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); - btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s - btScalar walkSpeed = walkVelocity * dt; - - _characterController->setWalkDirection(walkDirection*walkSpeed); - */ -} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9e425e2ec8..f0102b2824 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -15,15 +15,6 @@ #include #include - -#include -#include -#include -#include -#include - - - #include "Avatar.h" class ModelItemID; @@ -252,11 +243,6 @@ private: void updateChatCircle(float deltaTime); void maybeUpdateBillboard(); void setGravity(const glm::vec3& gravity); - - /// character collisions - btCharacterControllerInterface* _characterController; - void setupAvatarCollision(); - void setAvatarMotion(); }; #endif // hifi_MyAvatar_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 10c7f42546..99dcedf9a7 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -13,6 +13,7 @@ #include "ShapeInfoUtil.h" #include "PhysicsHelpers.h" #include "ThreadSafeDynamicsWorld.h" +#include "AvatarData.h" static uint32_t _numSubsteps; @@ -582,3 +583,45 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio body->activate(); return true; } + + + +void PhysicsEngine::setAvatarData(AvatarData *avatarData) { + btTransform startTransform = btTransform (glmToBullet(avatarData->getOrientation()), + glmToBullet(avatarData->getPosition())); + + class btPairCachingGhostObject* m_ghostObject = new btPairCachingGhostObject(); + m_ghostObject->setWorldTransform(startTransform); + + btScalar characterHeight = 1.75; + btScalar characterWidth = 1.75; + btScalar stepHeight = btScalar(0.35); + + btConvexShape* capsule = new btCapsuleShape(characterWidth, characterHeight); + m_ghostObject->setCollisionShape(capsule); + m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + + _characterController = new btKinematicCharacterController(m_ghostObject, capsule, stepHeight); + + // PhysicsSimulation _physicsSimulation + // PhysicsEngine --> ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; + // PhysicsEngine Application::_physicsEngine + + // ThreadSafeDynamicsWorld* dynamicsWorld; + // dynamicsWorld = Application::getInstance()->_physicsEngine; + _dynamicsWorld->addCollisionObject(m_ghostObject, btBroadphaseProxy::CharacterFilter, + btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + _dynamicsWorld->addAction(_characterController); +} + + +// void PhysicsEngine::setAvatarMotion(AvatarData *avatarData) { + /* + float dt = getDeltaTimeMicroseconds() * 0.000001f; + btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); + btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s + btScalar walkSpeed = walkVelocity * dt; + + _characterController->setWalkDirection(walkDirection*walkSpeed); + */ +// } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 2a7baa3ec6..1725b36314 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -16,6 +16,11 @@ #include #include +#include +#include +#include +#include +#include #include #include @@ -25,6 +30,7 @@ #include "EntityMotionState.h" #include "ShapeManager.h" #include "ThreadSafeDynamicsWorld.h" +#include "AvatarData.h" const float HALF_SIMULATION_EXTENT = 512.0f; // meters @@ -82,6 +88,8 @@ public: /// process queue of changed from external sources void relayIncomingChangesToSimulation(); + void setAvatarData(AvatarData *avatarData); + private: /// \param motionState pointer to Object's MotionState void removeObjectFromBullet(ObjectMotionState* motionState); @@ -113,6 +121,9 @@ private: ContactMap _contactMap; uint32_t _numContactFrames = 0; uint32_t _lastNumSubstepsAtUpdateInternal = 0; + + /// character collisions + btCharacterControllerInterface* _characterController; }; #endif // hifi_PhysicsEngine_h From b4998e9c53bfebccbbfd0e6edd8a05332399bfd5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Mar 2015 08:48:48 -0800 Subject: [PATCH 03/43] falling onto an object works --- interface/src/avatar/MyAvatar.cpp | 26 ++++++++++++++++++++++++- interface/src/avatar/MyAvatar.h | 1 + libraries/physics/src/PhysicsEngine.cpp | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f212402294..3068bd2046 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -181,7 +181,11 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); - updatePosition(deltaTime); + if (_enablePhysics) { + updatePhysicsPosition(deltaTime); + } else { + updatePosition(deltaTime); + } } { @@ -1391,6 +1395,26 @@ void MyAvatar::updatePosition(float deltaTime) { measureMotionDerivatives(deltaTime); } + +void MyAvatar::updatePhysicsPosition(float deltaTime) { + glm::vec3 velocity = _velocity; + + bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; + + glm::quat rotation = getHead()->getCameraOrientation(); + glm::vec3 localVelocity = glm::inverse(rotation) * velocity; + + bool hasFloor = false; + glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); + newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); + + // rotate back into world-frame + velocity = rotation * newLocalVelocity; + +} + + + void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { glm::vec3 up = getBodyUpDirection(); const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f2f965032d..d74b7fc5ac 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -235,6 +235,7 @@ private: glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor); glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); + void updatePhysicsPosition(float deltaTime); void updateCollisionWithAvatars(float deltaTime); void updateCollisionWithEnvironment(float deltaTime, float radius); void updateCollisionWithVoxels(float deltaTime, float radius); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 2cfa50b44d..63e6901ec4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -370,7 +370,7 @@ void PhysicsEngine::computeCollisionEvents() { btBroadphasePairArray& pairArray = _avatarGhostObject->getOverlappingPairCache()->getOverlappingPairArray(); int numPairs = pairArray.size(); - for (int i=0;i Date: Wed, 4 Mar 2015 15:26:02 -0800 Subject: [PATCH 04/43] move _velocity into base class. walking on a cube works --- interface/src/avatar/Avatar.cpp | 1 - interface/src/avatar/Avatar.h | 3 --- interface/src/avatar/MyAvatar.cpp | 22 +++++++++++++--------- interface/src/avatar/MyAvatar.h | 4 +--- libraries/avatars/src/AvatarData.cpp | 3 ++- libraries/avatars/src/AvatarData.h | 4 ++++ libraries/physics/src/PhysicsEngine.cpp | 17 +++-------------- 7 files changed, 23 insertions(+), 31 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index cac071a677..3333c0ab92 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -63,7 +63,6 @@ Avatar::Avatar() : _skeletonModel(this), _skeletonOffset(0.0f), _bodyYawDelta(0.0f), - _velocity(0.0f), _positionDeltaAccumulator(0.0f), _lastVelocity(0.0f), _acceleration(0.0f), diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 77c9459999..2951208d95 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -155,7 +155,6 @@ public: Q_INVOKABLE glm::vec3 getNeckPosition() const; - Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; } Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; } @@ -184,8 +183,6 @@ protected: QVector _attachmentModels; float _bodyYawDelta; - glm::vec3 _velocity; - // These position histories and derivatives are in the world-frame. // The derivatives are the MEASURED results of all external and internal forces // and are therefore READ-ONLY --> motion control of the Avatar is NOT obtained diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3068bd2046..e6f84330bc 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -181,8 +181,8 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); - if (_enablePhysics) { - updatePhysicsPosition(deltaTime); + if (isPhysicsEnabled()) { + updatePositionWithPhysics(deltaTime); } else { updatePosition(deltaTime); } @@ -1396,21 +1396,25 @@ void MyAvatar::updatePosition(float deltaTime) { } -void MyAvatar::updatePhysicsPosition(float deltaTime) { - glm::vec3 velocity = _velocity; - - bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; +void MyAvatar::updatePositionWithPhysics(float deltaTime) { + // bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; + // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); - glm::vec3 localVelocity = glm::inverse(rotation) * velocity; + glm::vec3 localVelocity = glm::inverse(rotation) * _velocity; bool hasFloor = false; glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); - // rotate back into world-frame - velocity = rotation * newLocalVelocity; + // cap avatar speed + float speed = glm::length(_velocity); + if (speed > MAX_AVATAR_SPEED) { + _velocity *= MAX_AVATAR_SPEED / speed; + } + // rotate back into world-frame + _velocity = rotation * newLocalVelocity; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d74b7fc5ac..6c55125b5c 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -166,8 +166,6 @@ public slots: glm::vec3 getThrust() { return _thrust; }; void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } - void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } - void updateMotionBehavior(); void onToggleRagdoll(); @@ -235,7 +233,7 @@ private: glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor); glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); - void updatePhysicsPosition(float deltaTime); + void updatePositionWithPhysics(float deltaTime); void updateCollisionWithAvatars(float deltaTime); void updateCollisionWithEnvironment(float deltaTime, float radius); void updateCollisionWithVoxels(float deltaTime, float radius); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a3d330f84b..5b391b33f8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -55,7 +55,8 @@ AvatarData::AvatarData() : _billboard(), _errorLogExpiry(0), _owningAvatarMixer(), - _lastUpdateTimer() + _lastUpdateTimer(), + _velocity(0.0f) { } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 857489eaa7..bc0305338c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -311,6 +311,8 @@ public: bool tryLockForWrite() { return _lock.tryLockForWrite(); } void unlock() { _lock.unlock(); } + void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } + Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } public slots: void sendAvatarDataPacket(); @@ -401,6 +403,8 @@ protected: virtual void updateJointMappings(); void changeReferential(Referential* ref); + glm::vec3 _velocity; + private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 63e6901ec4..d7df649713 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -284,6 +284,7 @@ void PhysicsEngine::stepSimulation() { if (_avatarData->isPhysicsEnabled()) { _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); + _characterController->setWalkDirection(glmToBullet(_avatarData->getVelocity())); } const int MAX_NUM_SUBSTEPS = 4; @@ -364,7 +365,7 @@ void PhysicsEngine::computeCollisionEvents() { } - +#if 0 // avatar collisions btManifoldArray manifoldArray; btBroadphasePairArray& pairArray = _avatarGhostObject->getOverlappingPairCache()->getOverlappingPairArray(); @@ -399,7 +400,7 @@ void PhysicsEngine::computeCollisionEvents() { } } } - +#endif @@ -667,15 +668,3 @@ void PhysicsEngine::setAvatarData(AvatarData *avatarData) { btGhostPairCallback* ghostPairCallback = new btGhostPairCallback(); _dynamicsWorld->getPairCache()->setInternalGhostPairCallback(ghostPairCallback); } - - -// void PhysicsEngine::setAvatarMotion() { - /* - float dt = getDeltaTimeMicroseconds() * 0.000001f; - btVector3 walkDirection = btVector3(0.0, 0.0, 0.0); - btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s - btScalar walkSpeed = walkVelocity * dt; - - _characterController->setWalkDirection(walkDirection*walkSpeed); - */ -// } From ac0c4e8512cc6f4ae752310c0c6816188b00e285 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Mar 2015 19:57:06 -0800 Subject: [PATCH 05/43] cap max speed at MAX_WALKING_SPEED --- interface/src/avatar/MyAvatar.cpp | 8 +++----- libraries/physics/src/PhysicsEngine.cpp | 13 +++++++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e6f84330bc..f30a22d78c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1397,8 +1397,6 @@ void MyAvatar::updatePosition(float deltaTime) { void MyAvatar::updatePositionWithPhysics(float deltaTime) { - // bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; - // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); glm::vec3 localVelocity = glm::inverse(rotation) * _velocity; @@ -1408,9 +1406,9 @@ void MyAvatar::updatePositionWithPhysics(float deltaTime) { newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); // cap avatar speed - float speed = glm::length(_velocity); - if (speed > MAX_AVATAR_SPEED) { - _velocity *= MAX_AVATAR_SPEED / speed; + float speed = glm::length(newLocalVelocity); + if (speed > MAX_WALKING_SPEED) { + newLocalVelocity *= MAX_WALKING_SPEED / speed; } // rotate back into world-frame diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index d7df649713..625afca683 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -281,18 +281,19 @@ void PhysicsEngine::stepSimulation() { // This is step (1). relayIncomingChangesToSimulation(); - if (_avatarData->isPhysicsEnabled()) { - _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); - _characterController->setWalkDirection(glmToBullet(_avatarData->getVelocity())); - } - const int MAX_NUM_SUBSTEPS = 4; const float MAX_TIMESTEP = (float)MAX_NUM_SUBSTEPS * PHYSICS_ENGINE_FIXED_SUBSTEP; float dt = 1.0e-6f * (float)(_clock.getTimeMicroseconds()); _clock.reset(); float timeStep = btMin(dt, MAX_TIMESTEP); + if (_avatarData->isPhysicsEnabled()) { + _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), + glmToBullet(_avatarData->getPosition()))); + // _characterController->setWalkDirection(glmToBullet(_avatarData->getVelocity())); + _characterController->setVelocityForTimeInterval(glmToBullet(_avatarData->getVelocity()), timeStep); + } + // This is step (2). int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); _numSubsteps += (uint32_t)numSubsteps; From af4957ff141609835f0890d1b668c7c134b15f26 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 Mar 2015 06:38:42 -0800 Subject: [PATCH 06/43] start to write out obj from vhacd --- tools/vhacd/src/VHACDUtil.cpp | 2 +- tools/vhacd/src/main.cpp | 47 +++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp index 63b3bba459..0f72032af1 100644 --- a/tools/vhacd/src/VHACDUtil.cpp +++ b/tools/vhacd/src/VHACDUtil.cpp @@ -14,7 +14,7 @@ //Read all the meshes from provided FBX file -bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results){ +bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) { // open the fbx file QFile fbx(filename); diff --git a/tools/vhacd/src/main.cpp b/tools/vhacd/src/main.cpp index e43f712fa0..530f4ad648 100644 --- a/tools/vhacd/src/main.cpp +++ b/tools/vhacd/src/main.cpp @@ -19,6 +19,22 @@ using namespace std; using namespace VHACD; + +bool writeOBJ(QString outFileName, QVector>& convexHullList) { + QFile file(outFileName); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "Unable to write to " << outFileName; + return false; + } + + QTextStream out(&file); + + out << "testing\n"; + + return true; +} + + int main(int argc, char * argv[]){ vector triangles; // array of indexes vector points; // array of coordinates @@ -27,17 +43,23 @@ int main(int argc, char * argv[]){ vhacd::ComputeResults results; // results after computing vhacd VHACD::IVHACD::Parameters params; vhacd::ProgressCallback pCallBack; - if (argc < 2){ - cout << "please provide a FBX file as argument\n "; + if (argc < 3) { + cout << argv[0] << " input-file.fbx output-file.obj\n"; return 1; } - string filename(argv[1]); - if (filename.empty()){ - cout << "please provide a FBX file as argument\n "; + string inputFilename(argv[1]); + if (inputFilename.empty()) { + cout << "please provide a FBX file as first argument\n"; + return 1; + } + string outputFilename(argv[2]); + if (outputFilename.empty()) { + cout << "please provide a OBJ file as second argument\n"; return 1; } - QString fname = QString::fromStdString(filename); + QString inFileName = QString::fromStdString(inputFilename); + QString outFileName = QString::fromStdString(outputFilename); //set parameters for V-HACD params.m_callback = &pCallBack; //progress callback @@ -53,7 +75,7 @@ int main(int argc, char * argv[]){ // load the mesh auto begin = std::chrono::high_resolution_clock::now(); - if (!vUtil.loadFBX(fname, &fbx)){ + if (!vUtil.loadFBX(inFileName, &fbx)){ cout << "Error in opening FBX file...."; return 1; } @@ -85,7 +107,7 @@ int main(int argc, char * argv[]){ totalHulls += hullCounts.at(i); } cout << endl << "Summary of V-HACD Computation..................." << endl; - cout << "File Path : " << fname.toStdString() << endl; + cout << "File Path : " << inFileName.toStdString() << endl; cout << "Number Of Meshes : " << fbx.meshCount << endl; cout << "Processed Meshes : " << results.meshCount << endl; cout << "Total vertices : " << totalVertices << endl; @@ -94,7 +116,7 @@ int main(int argc, char * argv[]){ cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl; cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl; cout << endl << "Summary per convex hull ........................" << endl < chList = results.convexHullList.at(i); cout << "\t" << "Number Of Hulls : " << chList.count() << endl; @@ -106,6 +128,9 @@ int main(int argc, char * argv[]){ } } - getchar(); + + writeOBJ(outFileName, results.convexHullList); + + return 0; -} \ No newline at end of file +} From 0d093b4921b5ae7e8dfcc6afc0924093eb8ac2f5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 5 Mar 2015 15:38:55 -0800 Subject: [PATCH 07/43] rename binary from vhacd to vhacd-util. vhacd-util outpus obj files --- tools/vhacd/CMakeLists.txt | 4 +- tools/vhacd/src/VHACDUtil.cpp | 22 +++ tools/vhacd/src/VHACDUtil.h | 16 +- tools/vhacd/src/VHACDUtilApp.cpp | 250 +++++++++++++++++++++++++++++++ tools/vhacd/src/VHACDUtilApp.h | 28 ++++ tools/vhacd/src/main.cpp | 119 +-------------- 6 files changed, 315 insertions(+), 124 deletions(-) create mode 100644 tools/vhacd/src/VHACDUtilApp.cpp create mode 100644 tools/vhacd/src/VHACDUtilApp.h diff --git a/tools/vhacd/CMakeLists.txt b/tools/vhacd/CMakeLists.txt index 31a7f7c8e2..f003b685e0 100644 --- a/tools/vhacd/CMakeLists.txt +++ b/tools/vhacd/CMakeLists.txt @@ -1,5 +1,5 @@ -set(TARGET_NAME vhacd) -setup_hifi_project() +set(TARGET_NAME vhacd-util) +setup_hifi_project(Core Widgets) link_hifi_libraries(shared model fbx gpu networking octree) #find_package(VHACD REQUIRED) done in CMakeList.txt in parent directory diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp index 0f72032af1..caa213572b 100644 --- a/tools/vhacd/src/VHACDUtil.cpp +++ b/tools/vhacd/src/VHACDUtil.cpp @@ -13,6 +13,11 @@ #include "VHACDUtil.h" + + + + + //Read all the meshes from provided FBX file bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) { @@ -82,6 +87,23 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD for (unsigned int j = 0; j < nConvexHulls; j++){ VHACD::IVHACD::ConvexHull hull; interfaceVHACD->GetConvexHull(j, hull); + + double *m_points_copy = new double[hull.m_nPoints * 3]; + // std::copy(std::begin(hull.m_points), std::end(hull.m_points), std::begin(m_points_copy)); + for (unsigned int i=0; iconvexHullList.append(convexHulls); diff --git a/tools/vhacd/src/VHACDUtil.h b/tools/vhacd/src/VHACDUtil.h index b87ba07ff0..ce1c157025 100644 --- a/tools/vhacd/src/VHACDUtil.h +++ b/tools/vhacd/src/VHACDUtil.h @@ -21,28 +21,28 @@ #include #include -namespace vhacd{ +namespace vhacd { - typedef struct{ + typedef struct { int meshCount; QVector convexHullsCountList; QVector> convexHullList; - }ComputeResults; + } ComputeResults; - typedef struct{ + typedef struct { int meshCount; QVector> perMeshVertices; QVector> perMeshTriangleIndices; - }LoadFBXResults; + } LoadFBXResults; - class VHACDUtil{ + class VHACDUtil { public: bool loadFBX(const QString filename, vhacd::LoadFBXResults *results); bool computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, vhacd::ComputeResults *results)const; ~VHACDUtil(); }; - class ProgressCallback : public VHACD::IVHACD::IUserCallback{ + class ProgressCallback : public VHACD::IVHACD::IUserCallback { public: ProgressCallback(void); ~ProgressCallback(); @@ -52,4 +52,4 @@ namespace vhacd{ const char * const stage, const char * const operation); }; } -#endif //hifi_VHACDUtil_h \ No newline at end of file +#endif //hifi_VHACDUtil_h diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp new file mode 100644 index 0000000000..d4b0f48766 --- /dev/null +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -0,0 +1,250 @@ +// +// VHACDUtil.h +// tools/vhacd/src +// +// Created by Seth Alves on 3/5/15. +// Copyright 2015 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 "VHACDUtilApp.h" +#include "VHACDUtil.h" + +using namespace std; +using namespace VHACD; + + + +QString formatFloat(double n) { + // limit precision to 6, but don't output trailing zeros. + QString s = QString::number(n, 'f', 6); + while (s.endsWith("0")) { + s.remove(s.size() - 1, 1); + } + if (s.endsWith(".")) { + s.remove(s.size() - 1, 1); + } + return s; +} + + +bool writeOBJ(QString outFileName, QVector>& convexHullList, bool outputOneMesh) { + QFile file(outFileName); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "Unable to write to " << outFileName; + return false; + } + + QTextStream out(&file); + + + if (convexHullList.size() != 1) { + qDebug() << "unexpected number of meshes --" << convexHullList.size(); + exit(1); + } + + QVector hulls = convexHullList[0]; + + + if (outputOneMesh) { + foreach (VHACD::IVHACD::ConvexHull hull, hulls) { + for (unsigned int i = 0; i < hull.m_nPoints; i++) { + out << "v "; + out << formatFloat(hull.m_points[i*3]) << " "; + out << formatFloat(hull.m_points[i*3+1]) << " "; + out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; + } + } + + unsigned int pointStartOffset = 0; + foreach (VHACD::IVHACD::ConvexHull hull, hulls) { + for (unsigned int i = 0; i < hull.m_nTriangles; i++) { + out << "f "; + out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; + out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; + out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n"; + } + pointStartOffset += hull.m_nPoints; + } + } else { + unsigned int nth = 0; + foreach (VHACD::IVHACD::ConvexHull hull, hulls) { + out << "o hull-" << nth++ << "\n"; + for (unsigned int i = 0; i < hull.m_nPoints; i++) { + out << "v "; + out << formatFloat(hull.m_points[i*3]) << " "; + out << formatFloat(hull.m_points[i*3+1]) << " "; + out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; + } + for (unsigned int i = 0; i < hull.m_nTriangles; i++) { + out << "f "; + out << hull.m_triangles[i*3] + 1 << " "; + out << hull.m_triangles[i*3+1] + 1 << " "; + out << hull.m_triangles[i*3+2] + 1 << "\n"; + } + out << "\n"; + } + } + + return true; +} + + + + +VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) : + QCoreApplication(argc, argv) +{ + vector triangles; // array of indexes + vector points; // array of coordinates + vhacd::VHACDUtil vUtil; + vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file + vhacd::ComputeResults results; // results after computing vhacd + VHACD::IVHACD::Parameters params; + vhacd::ProgressCallback pCallBack; + + + // parse command-line + QCommandLineParser parser; + parser.setApplicationDescription("High Fidelity Object Decomposer"); + parser.addHelpOption(); + + const QCommandLineOption helpOption = parser.addHelpOption(); + + const QCommandLineOption outputOneMeshOption("1", "output hulls as single mesh"); + parser.addOption(outputOneMeshOption); + + const QCommandLineOption inputFilenameOption("i", "input file", "filename.fbx"); + parser.addOption(inputFilenameOption); + + const QCommandLineOption outputFilenameOption("o", "output file", "filename.obj"); + parser.addOption(outputFilenameOption); + + + if (!parser.parse(QCoreApplication::arguments())) { + qCritical() << parser.errorText() << endl; + parser.showHelp(); + Q_UNREACHABLE(); + } + + if (parser.isSet(helpOption)) { + parser.showHelp(); + Q_UNREACHABLE(); + } + + + bool outputOneMesh = parser.isSet(outputOneMeshOption); + + QString inputFilename; + // check for an assignment pool passed on the command line or in the config + if (parser.isSet(inputFilenameOption)) { + inputFilename = parser.value(inputFilenameOption); + } + + QString outputFilename; + // check for an assignment pool passed on the command line or in the config + if (parser.isSet(outputFilenameOption)) { + outputFilename = parser.value(outputFilenameOption); + } + + + if (inputFilename == "") { + cerr << "input filename is required."; + parser.showHelp(); + Q_UNREACHABLE(); + } + + if (outputFilename == "") { + cerr << "output filename is required."; + parser.showHelp(); + Q_UNREACHABLE(); + } + + + //set parameters for V-HACD + params.m_callback = &pCallBack; //progress callback + params.m_resolution = 100000; // 100000 + params.m_depth = 20; // 20 + params.m_concavity = 0.001; // 0.001 + params.m_delta = 0.01; // 0.05 + params.m_planeDownsampling = 4; // 4 + params.m_convexhullDownsampling = 4; // 4 + params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes + params.m_beta = 0.05; // 0.05 + params.m_gamma = 0.0005; // 0.0005 + params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition + params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based + params.m_maxNumVerticesPerCH = 64; // 64 + params.m_minVolumePerCH = 0.00001; // 0.0001 + params.m_callback = 0; // 0 + params.m_logger = 0; // 0 + params.m_convexhullApproximation = true; // true + params.m_oclAcceleration = true; // true + + + + // load the mesh + + auto begin = std::chrono::high_resolution_clock::now(); + if (!vUtil.loadFBX(inputFilename, &fbx)){ + cout << "Error in opening FBX file...."; + } + auto end = std::chrono::high_resolution_clock::now(); + auto loadDuration = std::chrono::duration_cast(end - begin).count(); + + //perform vhacd computation + begin = std::chrono::high_resolution_clock::now(); + + + if (!vUtil.computeVHACD(&fbx, params, &results)){ + cout << "Compute Failed..."; + } + end = std::chrono::high_resolution_clock::now(); + auto computeDuration = std::chrono::duration_cast(end - begin).count(); + + int totalVertices = 0; + for (int i = 0; i < fbx.meshCount; i++){ + totalVertices += fbx.perMeshVertices.at(i).count(); + } + + int totalTriangles = 0; + for (int i = 0; i < fbx.meshCount; i++){ + totalTriangles += fbx.perMeshTriangleIndices.at(i).count(); + } + + int totalHulls = 0; + QVector hullCounts = results.convexHullsCountList; + for (int i = 0; i < results.meshCount; i++){ + totalHulls += hullCounts.at(i); + } + cout << endl << "Summary of V-HACD Computation..................." << endl; + cout << "File Path : " << inputFilename.toStdString() << endl; + cout << "Number Of Meshes : " << fbx.meshCount << endl; + cout << "Processed Meshes : " << results.meshCount << endl; + cout << "Total vertices : " << totalVertices << endl; + cout << "Total Triangles : " << totalTriangles << endl; + cout << "Total Convex Hulls : " << totalHulls << endl; + cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl; + cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl; + cout << endl << "Summary per convex hull ........................" << endl < chList = results.convexHullList.at(i); + cout << "\t" << "Number Of Hulls : " << chList.count() << endl; + + for (int j = 0; j < results.convexHullList.at(i).count(); j++){ + cout << "\tHUll : " << j + 1 << endl; + cout << "\t\tNumber Of Points : " << chList.at(j).m_nPoints << endl; + cout << "\t\tNumber Of Triangles : " << chList.at(j).m_nTriangles << endl; + } + } + + writeOBJ(outputFilename, results.convexHullList, outputOneMesh); +} + +VHACDUtilApp::~VHACDUtilApp() { +} diff --git a/tools/vhacd/src/VHACDUtilApp.h b/tools/vhacd/src/VHACDUtilApp.h new file mode 100644 index 0000000000..016b7b7b2f --- /dev/null +++ b/tools/vhacd/src/VHACDUtilApp.h @@ -0,0 +1,28 @@ +// +// VHACDUtil.h +// tools/vhacd/src +// +// Created by Seth Alves on 3/5/15. +// Copyright 2015 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_VHACDUtilApp_h +#define hifi_VHACDUtilApp_h + +#include + + +class VHACDUtilApp : public QCoreApplication { + Q_OBJECT + public: + VHACDUtilApp(int argc, char* argv[]); + ~VHACDUtilApp(); +}; + + + +#endif //hifi_VHACDUtilApp_h diff --git a/tools/vhacd/src/main.cpp b/tools/vhacd/src/main.cpp index 530f4ad648..0e8d72abd3 100644 --- a/tools/vhacd/src/main.cpp +++ b/tools/vhacd/src/main.cpp @@ -8,129 +8,20 @@ // 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 #include #include -#include "VHACDUtil.h" + +#include "VHACDUtilApp.h" using namespace std; using namespace VHACD; -bool writeOBJ(QString outFileName, QVector>& convexHullList) { - QFile file(outFileName); - if (!file.open(QIODevice::WriteOnly)) { - qDebug() << "Unable to write to " << outFileName; - return false; - } - - QTextStream out(&file); - - out << "testing\n"; - - return true; -} - - -int main(int argc, char * argv[]){ - vector triangles; // array of indexes - vector points; // array of coordinates - vhacd::VHACDUtil vUtil; - vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file - vhacd::ComputeResults results; // results after computing vhacd - VHACD::IVHACD::Parameters params; - vhacd::ProgressCallback pCallBack; - if (argc < 3) { - cout << argv[0] << " input-file.fbx output-file.obj\n"; - return 1; - } - string inputFilename(argv[1]); - if (inputFilename.empty()) { - cout << "please provide a FBX file as first argument\n"; - return 1; - } - string outputFilename(argv[2]); - if (outputFilename.empty()) { - cout << "please provide a OBJ file as second argument\n"; - return 1; - } - - QString inFileName = QString::fromStdString(inputFilename); - QString outFileName = QString::fromStdString(outputFilename); - - //set parameters for V-HACD - params.m_callback = &pCallBack; //progress callback - params.m_resolution = 50000; - params.m_depth = 10; - params.m_concavity = 0.003; - params.m_alpha = 0.05; // controls the bias toward clipping along symmetry planes - params.m_pca = 1; // enable/disable normalizing the mesh before applying the convex decomposition - params.m_mode = 1; // 0: voxel - based approximate convex decomposition, 1 : tetrahedron - based approximate convex decomposition - params.m_maxNumVerticesPerCH = 128; - params.m_minVolumePerCH = 0.0001; // controls the adaptive sampling of the generated convex - hulls - - // load the mesh - - auto begin = std::chrono::high_resolution_clock::now(); - if (!vUtil.loadFBX(inFileName, &fbx)){ - cout << "Error in opening FBX file...."; - return 1; - } - auto end = std::chrono::high_resolution_clock::now(); - auto loadDuration = std::chrono::duration_cast(end - begin).count(); - - //perform vhacd computation - begin = std::chrono::high_resolution_clock::now(); - if (!vUtil.computeVHACD(&fbx, params, &results)){ - cout << "Compute Failed..."; - return 1; - } - end = std::chrono::high_resolution_clock::now(); - auto computeDuration = std::chrono::duration_cast(end - begin).count(); - - int totalVertices = 0; - for (int i = 0; i < fbx.meshCount; i++){ - totalVertices += fbx.perMeshVertices.at(i).count(); - } - - int totalTriangles = 0; - for (int i = 0; i < fbx.meshCount; i++){ - totalTriangles += fbx.perMeshTriangleIndices.at(i).count(); - } - - int totalHulls = 0; - QVector hullCounts = results.convexHullsCountList; - for (int i = 0; i < results.meshCount; i++){ - totalHulls += hullCounts.at(i); - } - cout << endl << "Summary of V-HACD Computation..................." << endl; - cout << "File Path : " << inFileName.toStdString() << endl; - cout << "Number Of Meshes : " << fbx.meshCount << endl; - cout << "Processed Meshes : " << results.meshCount << endl; - cout << "Total vertices : " << totalVertices << endl; - cout << "Total Triangles : " << totalTriangles << endl; - cout << "Total Convex Hulls : " << totalHulls << endl; - cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl; - cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl; - cout << endl << "Summary per convex hull ........................" << endl < chList = results.convexHullList.at(i); - cout << "\t" << "Number Of Hulls : " << chList.count() << endl; - - for (int j = 0; j < results.convexHullList.at(i).count(); j++){ - cout << "\tHUll : " << j + 1 << endl; - cout << "\t\tNumber Of Points : " << chList.at(j).m_nPoints << endl; - cout << "\t\tNumber Of Triangles : " << chList.at(j).m_nTriangles << endl; - } - } - - - writeOBJ(outFileName, results.convexHullList); - - +int main(int argc, char * argv[]) { + VHACDUtilApp app(argc, argv); return 0; } From 858d15d0ba8191efd304589b09ff8860f47c6fc3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 6 Mar 2015 13:15:53 -0800 Subject: [PATCH 08/43] obj reader sort-of works --- libraries/fbx/src/OBJReader.cpp | 190 +++++++++++++++++++ libraries/fbx/src/OBJReader.h | 6 + libraries/render-utils/src/GeometryCache.cpp | 2 + libraries/render-utils/src/GeometryCache.h | 1 + tools/vhacd/src/VHACDUtil.cpp | 32 +++- tools/vhacd/src/VHACDUtil.h | 1 + tools/vhacd/src/VHACDUtilApp.cpp | 42 ++-- 7 files changed, 233 insertions(+), 41 deletions(-) create mode 100644 libraries/fbx/src/OBJReader.cpp create mode 100644 libraries/fbx/src/OBJReader.h diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp new file mode 100644 index 0000000000..1ff4f7a2ae --- /dev/null +++ b/libraries/fbx/src/OBJReader.cpp @@ -0,0 +1,190 @@ + + +#include +#include + + +#include "FBXReader.h" +#include "OBJReader.h" + + + +class OBJTokenizer { +public: + OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { } + enum SpecialToken { DATUM_TOKEN = 0x100 }; + int nextToken(); + const QByteArray& getDatum() const { return _datum; } + void skipLine() { _device->readLine(); } + void pushBackToken(int token) { _pushedBackToken = token; } + void ungetChar(char ch) { _device->ungetChar(ch); } + +private: + QIODevice* _device; + QByteArray _datum; + int _pushedBackToken; +}; + +int OBJTokenizer::nextToken() { + if (_pushedBackToken != -1) { + int token = _pushedBackToken; + _pushedBackToken = -1; + return token; + } + + char ch; + while (_device->getChar(&ch)) { + if (QChar(ch).isSpace()) { + continue; // skip whitespace + } + switch (ch) { + case '#': + _device->readLine(); // skip the comment + break; + + case '\"': + _datum = ""; + while (_device->getChar(&ch)) { + if (ch == '\"') { // end on closing quote + break; + } + if (ch == '\\') { // handle escaped quotes + if (_device->getChar(&ch) && ch != '\"') { + _datum.append('\\'); + } + } + _datum.append(ch); + } + return DATUM_TOKEN; + + default: + _datum = ""; + _datum.append(ch); + while (_device->getChar(&ch)) { + if (QChar(ch).isSpace() || ch == '\"') { + ungetChar(ch); // read until we encounter a special character, then replace it + break; + } + _datum.append(ch); + } + + return DATUM_TOKEN; + } + } + return -1; +} + + + +bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry, int& indexStart) { + FBXMesh mesh; + FBXMeshPart meshPart; + bool sawG = false; + bool meshHasData = true; + bool result = true; + + try { // XXX move this out/up + while (true) { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + result = false; + break; + } + QByteArray token = tokenizer.getDatum(); + if (token == "g") { + if (sawG) { + // we've encountered the beginning of the next group. + tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); + break; + } + sawG = true; + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + QByteArray groupName = tokenizer.getDatum(); + meshPart.materialID = groupName; + meshHasData = true; + } else if (token == "v") { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float x = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float y = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float z = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + + // float w = 1.0; + try{ + // w = + std::stof(tokenizer.getDatum().data()); + } + catch(const std::exception& e){ + // next token wasn't a number (the w field is optional), push it back + tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); + } + + mesh.vertices.append(glm::vec3(x, y, z)); + meshHasData = true; + } else if (token == "f") { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + int p0 = std::stoi(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + int p1 = std::stoi(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + int p2 = std::stoi(tokenizer.getDatum().data()); + + // obj indexes is 1 based and index over the entire file. mesh indexes are 0 based + // and index within the mesh. + meshPart.triangleIndices.append(p0 - 1 - indexStart); // obj index is 1 based + meshPart.triangleIndices.append(p1 - 1 - indexStart); + meshPart.triangleIndices.append(p2 - 1 - indexStart); + meshHasData = true; + } else { + // something we don't (yet) care about + qDebug() << "skipping line with" << token; + tokenizer.skipLine(); + } + } + } + catch(const std::exception& e) { + // something went wrong, stop here. + qDebug() << "something went wrong"; + return false; + } + + if (meshHasData) { + mesh.parts.append(meshPart); + geometry.meshes.append(mesh); + } + + indexStart += mesh.vertices.count(); + + return result; +} + + + +FBXGeometry extractOBJGeometry(const FBXNode& node, const QVariantHash& mapping) { + FBXGeometry geometry; + return geometry; +} + + + +FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) { + QBuffer buffer(const_cast(&model)); + buffer.open(QIODevice::ReadOnly); + return readOBJ(&buffer, mapping); +} + + +FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { + FBXGeometry geometry; + OBJTokenizer tokenizer(device); + int indexStart = 0; + + while (true) { + if (!parseOBJMesh(tokenizer, mapping, geometry, indexStart)) { + break; + } + } + + return geometry; +} diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h new file mode 100644 index 0000000000..2ff55a9a61 --- /dev/null +++ b/libraries/fbx/src/OBJReader.h @@ -0,0 +1,6 @@ + + +#include "FBXReader.h" + +FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping); +FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 9ecdfa43e1..1b773f2bf9 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -2101,6 +2101,8 @@ void GeometryReader::run() { lightmapLevel = 3.5f; } fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel); + } else if (_url.path().toLower().endsWith(".obj")) { + fbxgeo = readOBJ(_reply, _mapping); } QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo)); } else { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 92b6d44b6c..ba7c16bc10 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -22,6 +22,7 @@ #include #include +#include #include diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp index caa213572b..4c8a9eb62d 100644 --- a/tools/vhacd/src/VHACDUtil.cpp +++ b/tools/vhacd/src/VHACDUtil.cpp @@ -13,11 +13,6 @@ #include "VHACDUtil.h" - - - - - //Read all the meshes from provided FBX file bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) { @@ -29,14 +24,31 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re std::cout << "Reading FBX.....\n"; QByteArray fbxContents = fbx.readAll(); - FBXGeometry geometry = readFBX(fbxContents, QVariantHash()); + + + FBXGeometry geometry; + + if (filename.toLower().endsWith(".obj")) { + geometry = readOBJ(fbxContents, QVariantHash()); + } else if (filename.toLower().endsWith(".fbx")) { + geometry = readFBX(fbxContents, QVariantHash()); + } else { + qDebug() << "unknown file extension"; + return false; + } + + //results->meshCount = geometry.meshes.count(); + qDebug() << "read in" << geometry.meshes.count() << "meshes"; + int count = 0; - foreach(FBXMesh mesh, geometry.meshes){ + foreach(FBXMesh mesh, geometry.meshes) { //get vertices for each mesh QVector vertices = mesh.vertices; + qDebug() << "vertex count is" << vertices.count(); + //get the triangle indices for each mesh QVector triangles; foreach(FBXMeshPart part, mesh.parts){ @@ -45,9 +57,9 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re } //only read meshes with triangles - if (triangles.count() <= 0){ - continue; - } + if (triangles.count() <= 0){ + continue; + } results->perMeshVertices.append(vertices); results->perMeshTriangleIndices.append(triangles); count++; diff --git a/tools/vhacd/src/VHACDUtil.h b/tools/vhacd/src/VHACDUtil.h index ce1c157025..b0b9da9720 100644 --- a/tools/vhacd/src/VHACDUtil.h +++ b/tools/vhacd/src/VHACDUtil.h @@ -19,6 +19,7 @@ #include //c++11 feature #include #include +#include #include namespace vhacd { diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index d4b0f48766..6d4bf5adcb 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -32,7 +32,7 @@ QString formatFloat(double n) { } -bool writeOBJ(QString outFileName, QVector>& convexHullList, bool outputOneMesh) { +bool writeOBJ(QString outFileName, QVector>& meshList, bool outputOneMesh) { QFile file(outFileName); if (!file.open(QIODevice::WriteOnly)) { qDebug() << "Unable to write to " << outFileName; @@ -41,52 +41,32 @@ bool writeOBJ(QString outFileName, QVector>& QTextStream out(&file); + // if (meshList.size() != 1) { + // qDebug() << "unexpected number of meshes --" << meshList.size(); + // exit(1); + // } + // QVector hulls = meshList[0]; - if (convexHullList.size() != 1) { - qDebug() << "unexpected number of meshes --" << convexHullList.size(); - exit(1); - } + unsigned int pointStartOffset = 0; - QVector hulls = convexHullList[0]; - - - if (outputOneMesh) { + foreach (QVector hulls, meshList) { + unsigned int nth = 0; foreach (VHACD::IVHACD::ConvexHull hull, hulls) { + out << "g hull-" << nth++ << "\n"; for (unsigned int i = 0; i < hull.m_nPoints; i++) { out << "v "; out << formatFloat(hull.m_points[i*3]) << " "; out << formatFloat(hull.m_points[i*3+1]) << " "; out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; } - } - - unsigned int pointStartOffset = 0; - foreach (VHACD::IVHACD::ConvexHull hull, hulls) { for (unsigned int i = 0; i < hull.m_nTriangles; i++) { out << "f "; out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n"; } - pointStartOffset += hull.m_nPoints; - } - } else { - unsigned int nth = 0; - foreach (VHACD::IVHACD::ConvexHull hull, hulls) { - out << "o hull-" << nth++ << "\n"; - for (unsigned int i = 0; i < hull.m_nPoints; i++) { - out << "v "; - out << formatFloat(hull.m_points[i*3]) << " "; - out << formatFloat(hull.m_points[i*3+1]) << " "; - out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; - } - for (unsigned int i = 0; i < hull.m_nTriangles; i++) { - out << "f "; - out << hull.m_triangles[i*3] + 1 << " "; - out << hull.m_triangles[i*3+1] + 1 << " "; - out << hull.m_triangles[i*3+2] + 1 << "\n"; - } out << "\n"; + pointStartOffset += hull.m_nPoints; } } From 591edc052738ddaf30d83b0d213d78b18af73943 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:51:47 -0800 Subject: [PATCH 09/43] _mesh instance variable doesn't appear to be in use. --- libraries/fbx/src/FBXReader.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 6912dd730f..ecce607575 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -152,8 +152,6 @@ public: bool hasSpecularTexture() const; bool hasEmissiveTexture() const; - - model::Mesh _mesh; }; /// A single animation frame extracted from an FBX document. From 8a4339e57f2ac2688225d1aeb0ae4edae0d0336e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:52:20 -0800 Subject: [PATCH 10/43] stray control-Ms --- libraries/model/src/model/Material.h | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 57e0f68a9c..2718b1dfa8 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -76,26 +76,26 @@ public: void setOpacity(float opacity); // Schema to access the attribute values of the material - class Schema { - public: - - Color _diffuse; - float _opacity; - Color _specular; - float _shininess; - Color _emissive; - float _spare0; - - Schema() : - _diffuse(0.5f), - _opacity(1.0f), - _specular(0.03f), - _shininess(0.1f), - _emissive(0.0f) - {} + class Schema { + public: + + Color _diffuse; + float _opacity; + Color _specular; + float _shininess; + Color _emissive; + float _spare0; + + Schema() : + _diffuse(0.5f), + _opacity(1.0f), + _specular(0.03f), + _shininess(0.1f), + _emissive(0.0f) + {} }; - const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } + const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } void setTextureView(MapChannel channel, const TextureView& texture); const TextureMap& getTextureMap() const { return _textureMap; } From 6772847d0bfb916558767805fad9ab7c61f39d23 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:52:39 -0800 Subject: [PATCH 11/43] make it so I don't have to count --- libraries/networking/src/Assignment.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index a3b810c4ac..26b38914ba 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -26,14 +26,14 @@ class Assignment : public NodeData { public: enum Type { - AudioMixerType, - AvatarMixerType, - AgentType, - UNUSED_0, - UNUSED_1, - UNUSED_2, - EntityServerType, - AllTypes + AudioMixerType = 0, + AvatarMixerType = 1, + AgentType = 2, + UNUSED_0 = 3, + UNUSED_1 = 4, + UNUSED_2 = 5, + EntityServerType = 6, + AllTypes = 7 }; enum Command { From d7c8f2224665174c4f34e51297534eab8e1c44cf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:53:04 -0800 Subject: [PATCH 12/43] stray control-Ms --- libraries/shared/src/AABox.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index d862957642..9beb0a85f2 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -72,9 +72,9 @@ public: AABox clamp(const glm::vec3& min, const glm::vec3& max) const; AABox clamp(float min, float max) const; - AABox& operator += (const glm::vec3& point); - AABox& operator += (const AABox& box); - + AABox& operator += (const glm::vec3& point); + AABox& operator += (const AABox& box); + bool isInvalid() const { return _corner == glm::vec3(std::numeric_limits::infinity()); } private: From 4a7dd2b3e6c935efa014a1818f4137a4f8232bb5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:53:25 -0800 Subject: [PATCH 13/43] allow downloading of obj files --- libraries/render-utils/src/GeometryCache.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 1b773f2bf9..b80cc04b3f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -2084,6 +2084,7 @@ void GeometryReader::run() { urlValid &= !urlname.isEmpty(); urlValid &= !_url.path().isEmpty(); urlValid &= _url.path().toLower().endsWith(".fbx") + || _url.path().toLower().endsWith(".obj") || _url.path().toLower().endsWith(".svo"); if (urlValid) { From adfacf1e9830611c78f6c8375752b5653946420f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:53:45 -0800 Subject: [PATCH 14/43] adjust debugging prints --- tools/vhacd/src/VHACDUtil.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/vhacd/src/VHACDUtil.cpp b/tools/vhacd/src/VHACDUtil.cpp index 4c8a9eb62d..bc9ad09bde 100644 --- a/tools/vhacd/src/VHACDUtil.cpp +++ b/tools/vhacd/src/VHACDUtil.cpp @@ -39,16 +39,13 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re //results->meshCount = geometry.meshes.count(); - - qDebug() << "read in" << geometry.meshes.count() << "meshes"; + // qDebug() << "read in" << geometry.meshes.count() << "meshes"; int count = 0; foreach(FBXMesh mesh, geometry.meshes) { //get vertices for each mesh QVector vertices = mesh.vertices; - qDebug() << "vertex count is" << vertices.count(); - //get the triangle indices for each mesh QVector triangles; foreach(FBXMeshPart part, mesh.parts){ From d642b52de3fdbd49b3f5d5c3d6bbc1b8c3d9e40c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:54:19 -0800 Subject: [PATCH 15/43] swap y and z coords because normal obj format has 3rd value as up --- tools/vhacd/src/VHACDUtilApp.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index 6d4bf5adcb..66ee71840f 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -41,12 +41,6 @@ bool writeOBJ(QString outFileName, QVector>& QTextStream out(&file); - // if (meshList.size() != 1) { - // qDebug() << "unexpected number of meshes --" << meshList.size(); - // exit(1); - // } - // QVector hulls = meshList[0]; - unsigned int pointStartOffset = 0; foreach (QVector hulls, meshList) { @@ -56,8 +50,9 @@ bool writeOBJ(QString outFileName, QVector>& for (unsigned int i = 0; i < hull.m_nPoints; i++) { out << "v "; out << formatFloat(hull.m_points[i*3]) << " "; + // swap y and z because up is 3rd value in OBJ + out << formatFloat(hull.m_points[i*3+2]) << "\n"; out << formatFloat(hull.m_points[i*3+1]) << " "; - out << formatFloat(hull.m_points[i*3+2]) << " 1\n"; } for (unsigned int i = 0; i < hull.m_nTriangles; i++) { out << "f "; From f807384dfe26ef729e78ed0b480844b094f6bef4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 07:55:04 -0800 Subject: [PATCH 16/43] build a joint and caclulate extents. obj models now show up, though not correctly. --- libraries/fbx/src/OBJReader.cpp | 158 ++++++++++++++++++++++++++------ 1 file changed, 130 insertions(+), 28 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 1ff4f7a2ae..55fcdca89e 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -1,12 +1,15 @@ + +// http://en.wikipedia.org/wiki/Wavefront_.obj_file + + #include #include - #include "FBXReader.h" #include "OBJReader.h" - +#include "Shape.h" class OBJTokenizer { @@ -83,6 +86,22 @@ bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeome bool meshHasData = true; bool result = true; + + // QString materialID; + // model::MaterialPointer _material; + + meshPart.materialID = "dontknow"; + // meshPart._material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(), 96.0f, 1.0f }; + meshPart._material = model::MaterialPointer(new model::Material()); + meshPart.opacity = 1.0; + + // material._material->setEmissive(material.emissive); + // material._material->setDiffuse(material.diffuse); + // material._material->setSpecular(material.specular); + // material._material->setShininess(material.shininess); + // material._material->setOpacity(material.opacity); + + try { // XXX move this out/up while (true) { if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { @@ -104,40 +123,55 @@ bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeome } else if (token == "v") { if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } float x = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - float y = std::stof(tokenizer.getDatum().data()); + // notice the order of z and y -- in OBJ files, up is the 3rd value if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } float z = std::stof(tokenizer.getDatum().data()); if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float y = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - // float w = 1.0; - try{ - // w = - std::stof(tokenizer.getDatum().data()); - } - catch(const std::exception& e){ - // next token wasn't a number (the w field is optional), push it back - tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); - } + // the spec gets vague here. might be w, might be a color... chop it off. + tokenizer.skipLine(); mesh.vertices.append(glm::vec3(x, y, z)); + mesh.colors.append(glm::vec3(1, 1, 1)); meshHasData = true; } else if (token == "f") { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - int p0 = std::stoi(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - int p1 = std::stoi(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - int p2 = std::stoi(tokenizer.getDatum().data()); + // a face can have 3 or more vertices + QVector indices; + while (true) { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { goto done; } + try { + int vertexIndex = std::stoi(tokenizer.getDatum().data()); + // negative indexes count backward from the current end of the vertex list + vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1); + // obj index is 1 based + vertexIndex = vertexIndex - 1 - indexStart; + assert(vertexIndex >= 0); + indices.append(vertexIndex); + } + catch(const std::exception& e) { + // wasn't a number, but it back. + tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); + break; + } + } - // obj indexes is 1 based and index over the entire file. mesh indexes are 0 based - // and index within the mesh. - meshPart.triangleIndices.append(p0 - 1 - indexStart); // obj index is 1 based - meshPart.triangleIndices.append(p1 - 1 - indexStart); - meshPart.triangleIndices.append(p2 - 1 - indexStart); + if (indices.count() == 3) { + meshPart.triangleIndices << indices; + } else if (indices.count() == 4) { + meshPart.quadIndices << indices; + } else { + qDebug() << "no support for more than 4 vertices on a face in OBJ files"; + } meshHasData = true; } else { // something we don't (yet) care about + // vp + // mtllib + // usemtl + // s 1, s off + qDebug() << "skipping line with" << token; tokenizer.skipLine(); } @@ -145,14 +179,78 @@ bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeome } catch(const std::exception& e) { // something went wrong, stop here. - qDebug() << "something went wrong"; + qDebug() << "something went wrong in obj reader"; return false; } - if (meshHasData) { - mesh.parts.append(meshPart); - geometry.meshes.append(mesh); + done: + +#if 0 + // add bogus normal data for this mesh + // mesh.normals.resize(mesh.vertices.count()); + mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); + mesh.tangents.fill(glm::vec3(0,0,0), mesh.vertices.count()); + int triCount = meshPart.triangleIndices.count() / 3; + for (int i = 0; i < triCount; i++) { + int p0Index = meshPart.triangleIndices[ i*3 ]; + int p1Index = meshPart.triangleIndices[ i*3+1 ]; + int p2Index = meshPart.triangleIndices[ i*3+2 ]; + + glm::vec3 p0 = mesh.vertices[ p0Index ]; + glm::vec3 p1 = mesh.vertices[ p1Index ]; + glm::vec3 p2 = mesh.vertices[ p2Index ]; + + glm::vec3 n = glm::cross(p2 - p0, p1 - p0); + glm::vec3 t = glm::cross(p2 - p0, n); + + mesh.normals[ p0Index ] = n; + mesh.normals[ p1Index ] = n; + mesh.normals[ p2Index ] = n; + + mesh.tangents[ p0Index ] = t; + mesh.tangents[ p1Index ] = t; + mesh.tangents[ p2Index ] = t; } +#endif + + + if (! meshHasData) + return result; + + + mesh.meshExtents.reset(); + foreach (const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + geometry.meshExtents.addPoint(vertex); + } + + mesh.parts.append(meshPart); + geometry.meshes.append(mesh); + + + geometry.joints.resize(1); + geometry.joints[ 0 ].isFree = false; + // geometry.joints[ 0 ].freeLineage; + geometry.joints[ 0 ].parentIndex = -1; + geometry.joints[ 0 ].distanceToParent = 0; + geometry.joints[ 0 ].boneRadius = 0; + geometry.joints[ 0 ].translation = glm::vec3(0, 0, 0); + // geometry.joints[ 0 ].preTransform = ; + geometry.joints[ 0 ].preRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].rotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].postRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[ 0 ].postTransform = ; + // geometry.joints[ 0 ].transform = ; + geometry.joints[ 0 ].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].inverseDefaultRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].inverseBindRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[ 0 ].bindTransform = ; + geometry.joints[ 0 ].name = "OBJ"; + geometry.joints[ 0 ].shapePosition = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].shapeRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].shapeType = SPHERE_SHAPE; + geometry.joints[ 0 ].isSkeletonJoint = false; indexStart += mesh.vertices.count(); @@ -180,10 +278,14 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { OBJTokenizer tokenizer(device); int indexStart = 0; + geometry.meshExtents.reset(); + while (true) { if (!parseOBJMesh(tokenizer, mapping, geometry, indexStart)) { break; } + + qDebug() << "indexStart is" << indexStart; } return geometry; From b96e455b72fc81db69405d77ebcf669c84e1f4a5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 11:27:27 -0800 Subject: [PATCH 17/43] uninitialized variable --- libraries/entities/src/EntitySimulation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index e7f2219c19..1eb4fdc951 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -35,7 +35,7 @@ const int DIRTY_SIMULATION_FLAGS = class EntitySimulation : public QObject { Q_OBJECT public: - EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { } + EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL), _nextExpiry(quint64(-1)) { } virtual ~EntitySimulation() { setEntityTree(NULL); } void lock() { _mutex.lock(); } From bb0f6b4d28cd4a5d0a2520a24e60e4c15c7405f8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 11:27:52 -0800 Subject: [PATCH 18/43] uninitialized variable --- libraries/networking/src/LimitedNodeList.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index cf5b2eef27..279d958082 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -48,7 +48,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _localSockAddr(), _publicSockAddr(), _stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT), - _packetStatTimer() + _packetStatTimer(), + _thisNodeCanAdjustLocks(false) { static bool firstCall = true; if (firstCall) { From 3642e93b3f121240972c22cbdec9cd595abb17f3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 11:28:09 -0800 Subject: [PATCH 19/43] keep triangles facing outward --- tools/vhacd/src/VHACDUtilApp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index 66ee71840f..bea1b48206 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -51,13 +51,14 @@ bool writeOBJ(QString outFileName, QVector>& out << "v "; out << formatFloat(hull.m_points[i*3]) << " "; // swap y and z because up is 3rd value in OBJ - out << formatFloat(hull.m_points[i*3+2]) << "\n"; - out << formatFloat(hull.m_points[i*3+1]) << " "; + out << formatFloat(hull.m_points[i*3+2]) << " "; + out << formatFloat(hull.m_points[i*3+1]) << "\n"; } for (unsigned int i = 0; i < hull.m_nTriangles; i++) { out << "f "; - out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; + // change order to flip normal (due to swapping y and z, above) out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " "; + out << hull.m_triangles[i*3] + 1 + pointStartOffset << " "; out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n"; } out << "\n"; From 05e0fe353677b0c9cbc474aad72196020782ed59 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 11:28:30 -0800 Subject: [PATCH 20/43] object display correctly now? --- libraries/fbx/src/OBJReader.cpp | 304 ++++++++++++++------------------ 1 file changed, 136 insertions(+), 168 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 55fcdca89e..c09cd3091b 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -2,6 +2,8 @@ // http://en.wikipedia.org/wiki/Wavefront_.obj_file +// http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/ +// http://paulbourke.net/dataformats/obj/ #include @@ -28,6 +30,7 @@ private: int _pushedBackToken; }; + int OBJTokenizer::nextToken() { if (_pushedBackToken != -1) { int token = _pushedBackToken; @@ -78,194 +81,99 @@ int OBJTokenizer::nextToken() { } - -bool parseOBJMesh(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry, int& indexStart) { - FBXMesh mesh; - FBXMeshPart meshPart; +bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry) { + FBXMesh &mesh = geometry.meshes[0]; + mesh.parts.append(FBXMeshPart()); + FBXMeshPart &meshPart = mesh.parts.last(); bool sawG = false; - bool meshHasData = true; bool result = true; - - // QString materialID; - // model::MaterialPointer _material; - - meshPart.materialID = "dontknow"; - // meshPart._material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(), 96.0f, 1.0f }; - meshPart._material = model::MaterialPointer(new model::Material()); + meshPart.materialID = QString("dontknow") + QString::number(mesh.parts.count()); meshPart.opacity = 1.0; + meshPart._material = model::MaterialPointer(new model::Material()); + meshPart._material->setDiffuse(glm::vec3(1.0, 1.0, 1.0)); + meshPart._material->setOpacity(1.0); + meshPart._material->setSpecular(glm::vec3(1.0, 1.0, 1.0)); + meshPart._material->setShininess(96.0); + meshPart._material->setEmissive(glm::vec3(0.0, 0.0, 0.0)); - // material._material->setEmissive(material.emissive); - // material._material->setDiffuse(material.diffuse); - // material._material->setSpecular(material.specular); - // material._material->setShininess(material.shininess); - // material._material->setOpacity(material.opacity); - - - try { // XXX move this out/up - while (true) { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { - result = false; + while (true) { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + result = false; + break; + } + QByteArray token = tokenizer.getDatum(); + if (token == "g") { + if (sawG) { + // we've encountered the beginning of the next group. + tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); break; } - QByteArray token = tokenizer.getDatum(); - if (token == "g") { - if (sawG) { - // we've encountered the beginning of the next group. + sawG = true; + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + QByteArray groupName = tokenizer.getDatum(); + meshPart.materialID = groupName; + } else if (token == "v") { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float x = std::stof(tokenizer.getDatum().data()); + // notice the order of z and y -- in OBJ files, up is the 3rd value + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float z = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + float y = std::stof(tokenizer.getDatum().data()); + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + // the spec gets vague here. might be w, might be a color... chop it off. + tokenizer.skipLine(); + mesh.vertices.append(glm::vec3(x, y, z)); + mesh.colors.append(glm::vec3(1, 1, 1)); + } else if (token == "f") { + // a face can have 3 or more vertices + QVector indices; + while (true) { + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { goto done; } + try { + int vertexIndex = std::stoi(tokenizer.getDatum().data()); + // negative indexes count backward from the current end of the vertex list + vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1); + // obj index is 1 based + assert(vertexIndex >= 1); + indices.append(vertexIndex - 1); + } + catch(const std::exception& e) { + // wasn't a number, but it back. tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); break; } - sawG = true; - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - QByteArray groupName = tokenizer.getDatum(); - meshPart.materialID = groupName; - meshHasData = true; - } else if (token == "v") { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - float x = std::stof(tokenizer.getDatum().data()); - // notice the order of z and y -- in OBJ files, up is the 3rd value - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - float z = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - float y = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } - - // the spec gets vague here. might be w, might be a color... chop it off. - tokenizer.skipLine(); - - mesh.vertices.append(glm::vec3(x, y, z)); - mesh.colors.append(glm::vec3(1, 1, 1)); - meshHasData = true; - } else if (token == "f") { - // a face can have 3 or more vertices - QVector indices; - while (true) { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { goto done; } - try { - int vertexIndex = std::stoi(tokenizer.getDatum().data()); - // negative indexes count backward from the current end of the vertex list - vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1); - // obj index is 1 based - vertexIndex = vertexIndex - 1 - indexStart; - assert(vertexIndex >= 0); - indices.append(vertexIndex); - } - catch(const std::exception& e) { - // wasn't a number, but it back. - tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); - break; - } - } - - if (indices.count() == 3) { - meshPart.triangleIndices << indices; - } else if (indices.count() == 4) { - meshPart.quadIndices << indices; - } else { - qDebug() << "no support for more than 4 vertices on a face in OBJ files"; - } - meshHasData = true; - } else { - // something we don't (yet) care about - // vp - // mtllib - // usemtl - // s 1, s off - - qDebug() << "skipping line with" << token; - tokenizer.skipLine(); } + + if (indices.count() == 3) { + // flip these around (because of the y/z swap above) so our triangles face outward + meshPart.triangleIndices.append(indices[0]); + meshPart.triangleIndices.append(indices[2]); + meshPart.triangleIndices.append(indices[1]); + } else if (indices.count() == 4) { + meshPart.quadIndices << indices; + } else { + qDebug() << "no support for more than 4 vertices on a face in OBJ files"; + } + } else { + // something we don't (yet) care about + qDebug() << "OBJ parser is skipping a line with" << token; + tokenizer.skipLine(); } } - catch(const std::exception& e) { - // something went wrong, stop here. - qDebug() << "something went wrong in obj reader"; - return false; - } done: - -#if 0 - // add bogus normal data for this mesh - // mesh.normals.resize(mesh.vertices.count()); - mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); - mesh.tangents.fill(glm::vec3(0,0,0), mesh.vertices.count()); - int triCount = meshPart.triangleIndices.count() / 3; - for (int i = 0; i < triCount; i++) { - int p0Index = meshPart.triangleIndices[ i*3 ]; - int p1Index = meshPart.triangleIndices[ i*3+1 ]; - int p2Index = meshPart.triangleIndices[ i*3+2 ]; - - glm::vec3 p0 = mesh.vertices[ p0Index ]; - glm::vec3 p1 = mesh.vertices[ p1Index ]; - glm::vec3 p2 = mesh.vertices[ p2Index ]; - - glm::vec3 n = glm::cross(p2 - p0, p1 - p0); - glm::vec3 t = glm::cross(p2 - p0, n); - - mesh.normals[ p0Index ] = n; - mesh.normals[ p1Index ] = n; - mesh.normals[ p2Index ] = n; - - mesh.tangents[ p0Index ] = t; - mesh.tangents[ p1Index ] = t; - mesh.tangents[ p2Index ] = t; - } -#endif - - - if (! meshHasData) - return result; - - - mesh.meshExtents.reset(); - foreach (const glm::vec3& vertex, mesh.vertices) { - mesh.meshExtents.addPoint(vertex); - geometry.meshExtents.addPoint(vertex); - } - - mesh.parts.append(meshPart); - geometry.meshes.append(mesh); - - - geometry.joints.resize(1); - geometry.joints[ 0 ].isFree = false; - // geometry.joints[ 0 ].freeLineage; - geometry.joints[ 0 ].parentIndex = -1; - geometry.joints[ 0 ].distanceToParent = 0; - geometry.joints[ 0 ].boneRadius = 0; - geometry.joints[ 0 ].translation = glm::vec3(0, 0, 0); - // geometry.joints[ 0 ].preTransform = ; - geometry.joints[ 0 ].preRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].rotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].postRotation = glm::quat(0, 0, 0, 1); - // geometry.joints[ 0 ].postTransform = ; - // geometry.joints[ 0 ].transform = ; - geometry.joints[ 0 ].rotationMin = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].inverseDefaultRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].inverseBindRotation = glm::quat(0, 0, 0, 1); - // geometry.joints[ 0 ].bindTransform = ; - geometry.joints[ 0 ].name = "OBJ"; - geometry.joints[ 0 ].shapePosition = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].shapeRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].shapeType = SPHERE_SHAPE; - geometry.joints[ 0 ].isSkeletonJoint = false; - - indexStart += mesh.vertices.count(); - return result; } - FBXGeometry extractOBJGeometry(const FBXNode& node, const QVariantHash& mapping) { FBXGeometry geometry; return geometry; } - FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); @@ -276,16 +184,76 @@ FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) { FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { FBXGeometry geometry; OBJTokenizer tokenizer(device); - int indexStart = 0; geometry.meshExtents.reset(); + geometry.meshes.append(FBXMesh()); - while (true) { - if (!parseOBJMesh(tokenizer, mapping, geometry, indexStart)) { - break; + try { + while (parseOBJGroup(tokenizer, mapping, geometry)) { } - qDebug() << "indexStart is" << indexStart; + FBXMesh &mesh = geometry.meshes[0]; + + mesh.meshExtents.reset(); + foreach (const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + geometry.meshExtents.addPoint(vertex); + } + + geometry.joints.resize(1); + geometry.joints[ 0 ].isFree = false; + // geometry.joints[ 0 ].freeLineage; + geometry.joints[ 0 ].parentIndex = -1; + geometry.joints[ 0 ].distanceToParent = 0; + geometry.joints[ 0 ].boneRadius = 0; + geometry.joints[ 0 ].translation = glm::vec3(0, 0, 0); + // geometry.joints[ 0 ].preTransform = ; + geometry.joints[ 0 ].preRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].rotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].postRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[ 0 ].postTransform = ; + // geometry.joints[ 0 ].transform = ; + geometry.joints[ 0 ].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].inverseDefaultRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].inverseBindRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[ 0 ].bindTransform = ; + geometry.joints[ 0 ].name = "OBJ"; + geometry.joints[ 0 ].shapePosition = glm::vec3(0, 0, 0); + geometry.joints[ 0 ].shapeRotation = glm::quat(0, 0, 0, 1); + geometry.joints[ 0 ].shapeType = SPHERE_SHAPE; + geometry.joints[ 0 ].isSkeletonJoint = false; + + // add bogus normal data for this mesh + mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); + mesh.tangents.fill(glm::vec3(0,0,0), mesh.vertices.count()); + + foreach (FBXMeshPart meshPart, mesh.parts) { + int triCount = meshPart.triangleIndices.count() / 3; + for (int i = 0; i < triCount; i++) { + int p0Index = meshPart.triangleIndices[ i*3 ]; + int p1Index = meshPart.triangleIndices[ i*3+1 ]; + int p2Index = meshPart.triangleIndices[ i*3+2 ]; + + glm::vec3 p0 = mesh.vertices[ p0Index ]; + glm::vec3 p1 = mesh.vertices[ p1Index ]; + glm::vec3 p2 = mesh.vertices[ p2Index ]; + + glm::vec3 n = glm::cross(p1 - p0, p2 - p0); + glm::vec3 t = glm::cross(p2 - p0, n); + + mesh.normals[ p0Index ] = n; + mesh.normals[ p1Index ] = n; + mesh.normals[ p2Index ] = n; + + mesh.tangents[ p0Index ] = t; + mesh.tangents[ p1Index ] = t; + mesh.tangents[ p2Index ] = t; + } + } + } + catch(const std::exception& e) { + qDebug() << "something went wrong in OBJ reader"; } return geometry; From 72ebae72c0f3a351ae772693a7617cf96bd76697 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:22:32 -0800 Subject: [PATCH 21/43] allow adding entities with model urls that end in .obj --- examples/editEntities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index e6d4534b86..689f73eed4 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -385,7 +385,7 @@ var toolBar = (function () { } else if (browseModelsButtonDown) { var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (browseModelsButton === toolBar.clicked(clickedOverlay)) { - url = Window.s3Browse(".*(fbx|FBX)"); + url = Window.s3Browse(".*(fbx|FBX|obj|OBJ)"); if (url !== null && url !== "") { addModel(url); } From f6948193f1967405a10ca7ec11005e58aedc7d82 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:24:11 -0800 Subject: [PATCH 22/43] add fields for collision model url --- examples/html/entityProperties.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index fd1a4e3821..f2c7d80cfd 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -138,6 +138,7 @@ var elModelSections = document.querySelectorAll(".model-section"); var elModelURL = document.getElementById("property-model-url"); + var elCollisionModelURL = document.getElementById("property-collision-model-url"); var elModelAnimationURL = document.getElementById("property-model-animation-url"); var elModelAnimationPlaying = document.getElementById("property-model-animation-playing"); var elModelAnimationFPS = document.getElementById("property-model-animation-fps"); @@ -267,6 +268,7 @@ } elModelURL.value = properties.modelURL; + elCollisionModelURL.value = properties.collisionModelURL; elModelAnimationURL.value = properties.animationURL; elModelAnimationPlaying.checked = properties.animationIsPlaying; elModelAnimationFPS.value = properties.animationFPS; @@ -391,6 +393,7 @@ elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff')); elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL')); + elCollisionModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionModelURL')); elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL')); elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying')); elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS')); @@ -622,6 +625,12 @@ +
+
Collision Model URL
+
+ +
+
Animation URL
From 1bf8054cecef9bc325390067669ac5cfa0e4410e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:24:50 -0800 Subject: [PATCH 23/43] Collision Model --- examples/libraries/ToolTip.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/libraries/ToolTip.js b/examples/libraries/ToolTip.js index f12525af57..680f617436 100644 --- a/examples/libraries/ToolTip.js +++ b/examples/libraries/ToolTip.js @@ -53,6 +53,7 @@ function Tooltip() { text += "ID: " + properties.id + "\n" if (properties.type == "Model") { text += "Model URL: " + properties.modelURL + "\n" + text += "Collision Model URL: " + properties.collisionModelURL + "\n" text += "Animation URL: " + properties.animationURL + "\n" text += "Animation is playing: " + properties.animationIsPlaying + "\n" if (properties.sittingPoints && properties.sittingPoints.length > 0) { From cdeda67942224b1f386f10cf704e61f4506549a6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:25:18 -0800 Subject: [PATCH 24/43] Collision Model url --- examples/libraries/entityPropertyDialogBox.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 0cb76276d8..8fb7c10e5b 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -49,6 +49,8 @@ EntityPropertyDialogBox = (function () { if (properties.type == "Model") { array.push({ label: "Model URL:", value: properties.modelURL }); index++; + array.push({ label: "Collision Model URL:", value: properties.collisionModelURL }); + index++; array.push({ label: "Animation URL:", value: properties.animationURL }); index++; array.push({ label: "Animation is playing:", type: "checkbox", value: properties.animationIsPlaying }); @@ -271,6 +273,7 @@ EntityPropertyDialogBox = (function () { properties.locked = array[index++].value; if (properties.type == "Model") { properties.modelURL = array[index++].value; + properties.collisionModelURL = array[index++].value; properties.animationURL = array[index++].value; var newAnimationIsPlaying = array[index++].value; From 9ec72e4902c51cb0a42ca084eb3566632ab6c6eb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:25:46 -0800 Subject: [PATCH 25/43] quiet warning on linux --- interface/src/Application.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f3d9c09a67..53d2ccd0b2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3916,8 +3916,8 @@ void Application::takeSnapshot() { } void Application::setVSyncEnabled() { - bool vsyncOn = Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn); #if defined(Q_OS_WIN) + bool vsyncOn = Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn); if (wglewGetExtension("WGL_EXT_swap_control")) { wglSwapIntervalEXT(vsyncOn); int swapInterval = wglGetSwapIntervalEXT(); @@ -3940,7 +3940,6 @@ void Application::setVSyncEnabled() { #else qDebug("V-Sync is FORCED ON on this system\n"); #endif - vsyncOn = true; // Turns off unused variable warning } bool Application::isVSyncOn() const { From 630b5dd03bc9c9e940360d3c9a78044b71196903 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:27:02 -0800 Subject: [PATCH 26/43] collisionModelURL property --- libraries/entities/src/EntityItemProperties.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index e53a6ede3d..51b6f2de21 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -39,6 +39,7 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(color, ), CONSTRUCT_PROPERTY(modelURL, ""), + CONSTRUCT_PROPERTY(collisionModelURL, ""), CONSTRUCT_PROPERTY(animationURL, ""), CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS), CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX), @@ -150,6 +151,7 @@ void EntityItemProperties::debugDump() const { qDebug() << " _position=" << _position.x << "," << _position.y << "," << _position.z; qDebug() << " _dimensions=" << getDimensions(); qDebug() << " _modelURL=" << _modelURL; + qDebug() << " _collisionModelURL=" << _collisionModelURL; qDebug() << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); props.debugDumpBits(); @@ -205,6 +207,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); + CHECK_PROPERTY_CHANGE(PROP_COLLISION_MODEL_URL, collisionModelURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); @@ -261,6 +264,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(visible); COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color); COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(collisionModelURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying); COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); @@ -334,6 +338,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible); COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(collisionModelURL, setCollisionModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS); @@ -512,6 +517,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem if (properties.getType() == EntityTypes::Model) { APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL()); + APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, properties.getCollisionModelURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex()); @@ -730,6 +736,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int if (properties.getType() == EntityTypes::Model) { READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL); + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COLLISION_MODEL_URL, setCollisionModelURL); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); @@ -796,6 +803,7 @@ void EntityItemProperties::markAllChanged() { _visibleChanged = true; _colorChanged = true; _modelURLChanged = true; + _collisionModelURLChanged = true; _animationURLChanged = true; _animationIsPlayingChanged = true; _animationFrameIndexChanged = true; From bcfd1d8a89e0c23e108f626ed7d4cbe1e3756b01 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:27:20 -0800 Subject: [PATCH 27/43] collisionModelURL property --- libraries/entities/src/EntityItemProperties.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 9bf3c93c2b..49c7cf1d08 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -93,6 +93,7 @@ enum EntityPropertyList { PROP_TEXT = PROP_MODEL_URL, PROP_LINE_HEIGHT = PROP_ANIMATION_URL, PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS, + PROP_COLLISION_MODEL_URL, }; typedef PropertyFlags EntityPropertyFlags; @@ -155,6 +156,7 @@ public: DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString); + DEFINE_PROPERTY_REF(PROP_COLLISION_MODEL_URL, CollisionModelURL, collisionModelURL, QString); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString); DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float); DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float); @@ -275,6 +277,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionModelURL, collisionModelURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFPS, animationFPS, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFrameIndex, animationFrameIndex, ""); From 58bd8a5c6502e1b3914e08bbf1e58089e7f5834b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:30:29 -0800 Subject: [PATCH 28/43] collision model url --- libraries/entities/src/ModelEntityItem.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index ed76b8c99f..026dc8af96 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -19,6 +19,7 @@ #include "ModelEntityItem.h" const QString ModelEntityItem::DEFAULT_MODEL_URL = QString(""); +const QString ModelEntityItem::DEFAULT_COLLISION_MODEL_URL = QString(""); const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString(""); const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; @@ -44,6 +45,7 @@ EntityItemProperties ModelEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionModelURL, getCollisionModelURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationURL, getAnimationURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying); COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex); @@ -61,6 +63,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionModelURL, setCollisionModelURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying); SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex); @@ -92,6 +95,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL); + if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { + setCollisionModelURL(""); + } else { + READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL); + } READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL); // Because we're using AnimationLoop which will reset the frame index if you change it's running state @@ -128,6 +136,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_MODEL_URL; + requestedProperties += PROP_COLLISION_MODEL_URL; requestedProperties += PROP_ANIMATION_URL; requestedProperties += PROP_ANIMATION_FPS; requestedProperties += PROP_ANIMATION_FRAME_INDEX; @@ -151,6 +160,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL()); + APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, getCollisionModelURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex()); @@ -258,6 +268,7 @@ void ModelEntityItem::debugDump() const { qDebug() << " position:" << getPosition() * (float)TREE_SCALE; qDebug() << " dimensions:" << getDimensions() * (float)TREE_SCALE; qDebug() << " model URL:" << getModelURL(); + qDebug() << " collision model URL:" << getCollisionModelURL(); } void ModelEntityItem::updateShapeType(ShapeType type) { From 96d94e1b0973ef5e587cd01ae0333892814990e4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:31:04 -0800 Subject: [PATCH 29/43] collision model url --- libraries/entities/src/ModelEntityItem.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 94d262fc9f..081cb429ed 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -57,10 +57,14 @@ public: const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } bool hasModel() const { return !_modelURL.isEmpty(); } + bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); } static const QString DEFAULT_MODEL_URL; const QString& getModelURL() const { return _modelURL; } + static const QString DEFAULT_COLLISION_MODEL_URL; + const QString& getCollisionModelURL() const { return _collisionModelURL; } + bool hasAnimation() const { return !_animationURL.isEmpty(); } static const QString DEFAULT_ANIMATION_URL; const QString& getAnimationURL() const { return _animationURL; } @@ -74,6 +78,7 @@ public: // model related properties void setModelURL(const QString& url) { _modelURL = url; } + void setCollisionModelURL(const QString& url) { _collisionModelURL = url; } void setAnimationURL(const QString& url); static const float DEFAULT_ANIMATION_FRAME_INDEX; void setAnimationFrameIndex(float value); @@ -121,6 +126,7 @@ protected: rgbColor _color; QString _modelURL; + QString _collisionModelURL; quint64 _lastAnimated; QString _animationURL; From 804d4a096336895e4c505284cc0c0bcefadd9587 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:31:37 -0800 Subject: [PATCH 30/43] coding standard --- libraries/fbx/src/OBJReader.cpp | 81 ++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c09cd3091b..6020bc861b 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -1,6 +1,13 @@ - - - +// +// EntityItemProperties.h +// libraries/entities/src +// +// Created by Seth Alves on 3/7/15. +// 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 +// // http://en.wikipedia.org/wiki/Wavefront_.obj_file // http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/ // http://paulbourke.net/dataformats/obj/ @@ -201,28 +208,28 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { } geometry.joints.resize(1); - geometry.joints[ 0 ].isFree = false; - // geometry.joints[ 0 ].freeLineage; - geometry.joints[ 0 ].parentIndex = -1; - geometry.joints[ 0 ].distanceToParent = 0; - geometry.joints[ 0 ].boneRadius = 0; - geometry.joints[ 0 ].translation = glm::vec3(0, 0, 0); - // geometry.joints[ 0 ].preTransform = ; - geometry.joints[ 0 ].preRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].rotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].postRotation = glm::quat(0, 0, 0, 1); - // geometry.joints[ 0 ].postTransform = ; - // geometry.joints[ 0 ].transform = ; - geometry.joints[ 0 ].rotationMin = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].inverseDefaultRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].inverseBindRotation = glm::quat(0, 0, 0, 1); - // geometry.joints[ 0 ].bindTransform = ; - geometry.joints[ 0 ].name = "OBJ"; - geometry.joints[ 0 ].shapePosition = glm::vec3(0, 0, 0); - geometry.joints[ 0 ].shapeRotation = glm::quat(0, 0, 0, 1); - geometry.joints[ 0 ].shapeType = SPHERE_SHAPE; - geometry.joints[ 0 ].isSkeletonJoint = false; + geometry.joints[0].isFree = false; + // geometry.joints[0].freeLineage; + geometry.joints[0].parentIndex = -1; + geometry.joints[0].distanceToParent = 0; + geometry.joints[0].boneRadius = 0; + geometry.joints[0].translation = glm::vec3(0, 0, 0); + // geometry.joints[0].preTransform = ; + geometry.joints[0].preRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].rotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].postRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[0].postTransform = ; + // geometry.joints[0].transform = ; + geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[0].inverseDefaultRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].inverseBindRotation = glm::quat(0, 0, 0, 1); + // geometry.joints[0].bindTransform = ; + geometry.joints[0].name = "OBJ"; + geometry.joints[0].shapePosition = glm::vec3(0, 0, 0); + geometry.joints[0].shapeRotation = glm::quat(0, 0, 0, 1); + geometry.joints[0].shapeType = SPHERE_SHAPE; + geometry.joints[0].isSkeletonJoint = false; // add bogus normal data for this mesh mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count()); @@ -231,24 +238,24 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { foreach (FBXMeshPart meshPart, mesh.parts) { int triCount = meshPart.triangleIndices.count() / 3; for (int i = 0; i < triCount; i++) { - int p0Index = meshPart.triangleIndices[ i*3 ]; - int p1Index = meshPart.triangleIndices[ i*3+1 ]; - int p2Index = meshPart.triangleIndices[ i*3+2 ]; + int p0Index = meshPart.triangleIndices[i*3]; + int p1Index = meshPart.triangleIndices[i*3+1]; + int p2Index = meshPart.triangleIndices[i*3+2]; - glm::vec3 p0 = mesh.vertices[ p0Index ]; - glm::vec3 p1 = mesh.vertices[ p1Index ]; - glm::vec3 p2 = mesh.vertices[ p2Index ]; + glm::vec3 p0 = mesh.vertices[p0Index]; + glm::vec3 p1 = mesh.vertices[p1Index]; + glm::vec3 p2 = mesh.vertices[p2Index]; glm::vec3 n = glm::cross(p1 - p0, p2 - p0); glm::vec3 t = glm::cross(p2 - p0, n); - mesh.normals[ p0Index ] = n; - mesh.normals[ p1Index ] = n; - mesh.normals[ p2Index ] = n; + mesh.normals[p0Index] = n; + mesh.normals[p1Index] = n; + mesh.normals[p2Index] = n; - mesh.tangents[ p0Index ] = t; - mesh.tangents[ p1Index ] = t; - mesh.tangents[ p2Index ] = t; + mesh.tangents[p0Index] = t; + mesh.tangents[p1Index] = t; + mesh.tangents[p2Index] = t; } } } From b8cdf1a31836f025d015a46c59c8dbd74be32bc2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:31:53 -0800 Subject: [PATCH 31/43] quiet warning --- libraries/networking/src/LimitedNodeList.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 85db739cda..afbdf23fba 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -216,7 +216,6 @@ protected: void handleNodeKill(const SharedNodePointer& node); QUuid _sessionUUID; - bool _thisNodeCanAdjustLocks; NodeHash _nodeHash; QReadWriteLock _nodeMutex; QUdpSocket _nodeSocket; @@ -230,6 +229,7 @@ protected: int _numCollectedBytes; QElapsedTimer _packetStatTimer; + bool _thisNodeCanAdjustLocks; template void eachNodeHashIterator(IteratorLambda functor) { From d713d5596ffcadffb6dfd64687362ed5be2df08d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:32:28 -0800 Subject: [PATCH 32/43] bump entity-data message version number --- libraries/networking/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index c9add10e5f..a14191bf09 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES; + return VERSION_ENTITIES_HAS_COLLISION_MODEL; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: From 1a1863679d22dee0ab94f8f1bf31b5b4ca9b7188 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:32:41 -0800 Subject: [PATCH 33/43] bump entity-data message version number --- libraries/networking/src/PacketHeaders.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index c89127058f..0b969182b0 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -130,5 +130,6 @@ const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7; const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8; const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = 9; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; +const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 10; #endif // hifi_PacketHeaders_h From e4baaa38b4f82af0f8e8ff5a5506345ef8b41001 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 7 Mar 2015 20:33:00 -0800 Subject: [PATCH 34/43] collision model url --- tests/octree/src/OctreeTests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/octree/src/OctreeTests.cpp b/tests/octree/src/OctreeTests.cpp index 4fc543d5d3..705a50aa10 100644 --- a/tests/octree/src/OctreeTests.cpp +++ b/tests/octree/src/OctreeTests.cpp @@ -32,6 +32,7 @@ enum ExamplePropertyList { EXAMPLE_PROP_POSITION, EXAMPLE_PROP_RADIUS, EXAMPLE_PROP_MODEL_URL, + EXAMPLE_PROP_COLLISION_MODEL_URL, EXAMPLE_PROP_ROTATION, EXAMPLE_PROP_COLOR, EXAMPLE_PROP_SCRIPT, @@ -73,6 +74,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) { props.setHasProperty(PROP_POSITION); props.setHasProperty(PROP_RADIUS); props.setHasProperty(PROP_MODEL_URL); + props.setHasProperty(PROP_COLLISION_MODEL_URL); props.setHasProperty(PROP_ROTATION); QByteArray encoded = props.encode(); From b2cfed8bcad7678e3028e0cd356d28e2913fcabf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 8 Mar 2015 09:04:00 -0700 Subject: [PATCH 35/43] removed unused blob of code --- libraries/physics/src/PhysicsEngine.cpp | 42 ------------------------- 1 file changed, 42 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 625afca683..501b39428a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -364,48 +364,6 @@ void PhysicsEngine::computeCollisionEvents() { } } } - - -#if 0 - // avatar collisions - btManifoldArray manifoldArray; - btBroadphasePairArray& pairArray = _avatarGhostObject->getOverlappingPairCache()->getOverlappingPairArray(); - int numPairs = pairArray.size(); - - for (int i = 0; i < numPairs; i++) { - manifoldArray.clear(); - const btBroadphasePair& pair = pairArray[i]; - // unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache: - btBroadphasePair* collisionPair = _dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0, pair.m_pProxy1); - if (!collisionPair) { - continue; - } - if (collisionPair->m_algorithm) { - collisionPair->m_algorithm->getAllContactManifolds(manifoldArray); - } - - for (int j=0;jgetBody0() == _avatarGhostObject ? btScalar(-1.0) : btScalar(1.0); - for (int p=0; pgetNumContacts(); p++) { - const btManifoldPoint& pt = manifold->getContactPoint(p); - if (pt.getDistance() < 0.f) { - - - const btVector3& ptA = pt.getPositionWorldOnA(); - const btVector3& ptB = pt.getPositionWorldOnB(); - const btVector3& normalOnB = pt.m_normalWorldOnB; - /// work here - qDebug() << "HERE"; - } - } - } - } -#endif - - - - // We harvest collision callbacks every few frames, which contributes the following effects: // From a180eadc91667aaa926e7ea4fd3fef60a3150b02 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 8 Mar 2015 18:07:07 -0700 Subject: [PATCH 36/43] remove stray control-Ms --- libraries/render-utils/src/Model.cpp | 228 +++++++++++++-------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index bbb4dfe8cf..83d98fa9b1 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -198,51 +198,51 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo locations.emissiveTextureUnit = -1; } - // bindable uniform version -#if defined(Q_OS_MAC) - loc = program.uniformLocation("materialBuffer"); - if (loc >= 0) { - locations.materialBufferUnit = loc; - } else { - locations.materialBufferUnit = -1; - } -#elif defined(Q_OS_WIN) - loc = glGetUniformBlockIndex(program.programId(), "materialBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, 1); - locations.materialBufferUnit = 1; - } else { - locations.materialBufferUnit = -1; - } -#else - loc = program.uniformLocation("materialBuffer"); - if (loc >= 0) { - locations.materialBufferUnit = loc; - } else { - locations.materialBufferUnit = -1; - } -#endif - -#if defined(Q_OS_WIN) - loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT); - // locations.materialBufferUnit = 1; - } -#endif - -#if defined(Q_OS_WIN) - loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT); - // locations.materialBufferUnit = 1; - } -#endif - + // bindable uniform version +#if defined(Q_OS_MAC) + loc = program.uniformLocation("materialBuffer"); + if (loc >= 0) { + locations.materialBufferUnit = loc; + } else { + locations.materialBufferUnit = -1; + } +#elif defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "materialBuffer"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, 1); + locations.materialBufferUnit = 1; + } else { + locations.materialBufferUnit = -1; + } +#else + loc = program.uniformLocation("materialBuffer"); + if (loc >= 0) { + locations.materialBufferUnit = loc; + } else { + locations.materialBufferUnit = -1; + } +#endif + +#if defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT); + // locations.materialBufferUnit = 1; + } +#endif + +#if defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT); + // locations.materialBufferUnit = 1; + } +#endif + //program.link(); - if (!program.isLinked()) { - program.release(); - } + if (!program.isLinked()) { + program.release(); + } program.release(); } @@ -303,70 +303,70 @@ void Model::init() { _program.addShaderFromSourceCode(QGLShader::Fragment, model_frag); initProgram(_program, _locations); - _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initProgram(_normalMapProgram, _normalMapLocations); - - _specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initProgram(_specularMapProgram, _specularMapLocations); - - _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); - - _translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); - initProgram(_translucentProgram, _translucentLocations); - - // Lightmap - _lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); - initProgram(_lightmapProgram, _lightmapLocations); - - _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); - initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); - - _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); - initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); - - _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); - initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); - // end lightmap - - - _shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); - _shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - // Shadow program uses the same locations as standard rendering path but we still need to set the bindings - Model::Locations tempLoc; - initProgram(_shadowProgram, tempLoc); - - _skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); - initSkinProgram(_skinProgram, _skinLocations); - - _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); - - _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); - - _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); - - _skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); - _skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - initSkinProgram(_skinShadowProgram, _skinShadowLocations); - - - _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); + _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); + _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); + initProgram(_normalMapProgram, _normalMapLocations); + + _specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); + initProgram(_specularMapProgram, _specularMapLocations); + + _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); + _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); + initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); + + _translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); + initProgram(_translucentProgram, _translucentLocations); + + // Lightmap + _lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); + _lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); + initProgram(_lightmapProgram, _lightmapLocations); + + _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); + _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); + initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); + + _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); + _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); + initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); + + _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); + _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); + initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); + // end lightmap + + + _shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); + _shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); + // Shadow program uses the same locations as standard rendering path but we still need to set the bindings + Model::Locations tempLoc; + initProgram(_shadowProgram, tempLoc); + + _skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); + _skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); + initSkinProgram(_skinProgram, _skinLocations); + + _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); + _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); + initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); + + _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); + initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); + + _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); + _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); + initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); + + _skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); + _skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); + initSkinProgram(_skinShadowProgram, _skinShadowLocations); + + + _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); + _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); } } @@ -2470,16 +2470,16 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod qDebug() << "part INDEX:" << j; qDebug() << "NEW part.materialID:" << part.materialID; } - - if (locations->glowIntensity >= 0) { - GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity()); + + if (locations->glowIntensity >= 0) { + GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity()); } if (!(translucent && alphaThreshold == 0.0f)) { GLBATCH(glAlphaFunc)(GL_EQUAL, glowEffect->getIntensity()); } - - if (locations->materialBufferUnit >= 0) { - batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); + + if (locations->materialBufferUnit >= 0) { + batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer()); } Texture* diffuseMap = networkPart.diffuseTexture.data(); From 3604fd639afb87c729d09f2a4b06237efa12bdf8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 8 Mar 2015 20:03:10 -0700 Subject: [PATCH 37/43] formatting --- interface/src/Application.cpp | 1 - interface/src/avatar/MyAvatar.cpp | 6 ++---- interface/src/avatar/MyAvatar.h | 2 -- libraries/avatars/src/AvatarData.h | 2 +- libraries/fbx/src/OBJReader.cpp | 4 ++-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e4501eac0e..23654e7745 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1817,7 +1817,6 @@ void Application::init() { auto entityScriptingInterface = DependencyManager::get(); - connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, entityScriptingInterface.data(), &EntityScriptingInterface::entityCollisionWithEntity); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5fb0b9dc5f..82aa4e8177 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -91,7 +91,8 @@ MyAvatar::MyAvatar() : _physicsSimulation(), _feetTouchFloor(true), _isLookingAtLeftEye(true), - _realWorldFieldOfView("realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES) + _realWorldFieldOfView("realWorldFieldOfView", + DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES) { ShapeCollider::initDispatchTable(); for (int i = 0; i < MAX_DRIVE_KEYS; i++) { @@ -1400,7 +1401,6 @@ void MyAvatar::updatePosition(float deltaTime) { measureMotionDerivatives(deltaTime); } - void MyAvatar::updatePositionWithPhysics(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); @@ -1420,8 +1420,6 @@ void MyAvatar::updatePositionWithPhysics(float deltaTime) { _velocity = rotation * newLocalVelocity; } - - void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { glm::vec3 up = getBodyUpDirection(); const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6c55125b5c..7e7281f6a1 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -19,8 +19,6 @@ class ModelItemID; - - class MyAvatar : public Avatar { Q_OBJECT Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index bc0305338c..c131588fb0 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -411,7 +411,7 @@ private: AvatarData& operator= (const AvatarData&); QReadWriteLock _lock; - bool _enablePhysics = false; // XXX + bool _enablePhysics = false; }; Q_DECLARE_METATYPE(AvatarData*) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 6020bc861b..668e62bf3a 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -1,6 +1,6 @@ // -// EntityItemProperties.h -// libraries/entities/src +// OBJReader.cpp +// libraries/fbx/src/ // // Created by Seth Alves on 3/7/15. // Copyright 2013 High Fidelity, Inc. From 0833fc588b64f892f3f71cfb62cd9370e4080026 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 9 Mar 2015 06:56:35 -0700 Subject: [PATCH 38/43] coding standard --- libraries/fbx/src/FBXReader.cpp | 14 ++++++++----- libraries/fbx/src/OBJReader.cpp | 14 +++++++++---- tools/vhacd/src/VHACDUtilApp.cpp | 34 +++++++++++++++----------------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index cbbaae3d82..a2c217c97d 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -295,7 +295,11 @@ public: Tokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { } - enum SpecialToken { DATUM_TOKEN = 0x100 }; + enum SpecialToken { + NO_TOKEN = -1, + NO_PUSHBACKED_TOKEN = -1, + DATUM_TOKEN = 0x100 + }; int nextToken(); const QByteArray& getDatum() const { return _datum; } @@ -311,9 +315,9 @@ private: }; int Tokenizer::nextToken() { - if (_pushedBackToken != -1) { + if (_pushedBackToken != NO_PUSHBACKED_TOKEN) { int token = _pushedBackToken; - _pushedBackToken = -1; + _pushedBackToken = NO_PUSHBACKED_TOKEN; return token; } @@ -361,7 +365,7 @@ int Tokenizer::nextToken() { return DATUM_TOKEN; } } - return -1; + return NO_TOKEN; } FBXNode parseTextFBXNode(Tokenizer& tokenizer) { @@ -378,7 +382,7 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) { int token; bool expectingDatum = true; - while ((token = tokenizer.nextToken()) != -1) { + while ((token = tokenizer.nextToken()) != Tokenizer::NO_TOKEN) { if (token == '{') { for (FBXNode child = parseTextFBXNode(tokenizer); !child.name.isNull(); child = parseTextFBXNode(tokenizer)) { node.children.append(child); diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 668e62bf3a..194aaa4ac0 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -24,7 +24,11 @@ class OBJTokenizer { public: OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { } - enum SpecialToken { DATUM_TOKEN = 0x100 }; + enum SpecialToken { + NO_TOKEN = -1, + NO_PUSHBACKED_TOKEN = -1, + DATUM_TOKEN = 0x100 + }; int nextToken(); const QByteArray& getDatum() const { return _datum; } void skipLine() { _device->readLine(); } @@ -39,9 +43,9 @@ private: int OBJTokenizer::nextToken() { - if (_pushedBackToken != -1) { + if (_pushedBackToken != NO_PUSHBACKED_TOKEN) { int token = _pushedBackToken; - _pushedBackToken = -1; + _pushedBackToken = NO_PUSHBACKED_TOKEN; return token; } @@ -84,7 +88,7 @@ int OBJTokenizer::nextToken() { return DATUM_TOKEN; } } - return -1; + return NO_TOKEN; } @@ -196,6 +200,8 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { geometry.meshes.append(FBXMesh()); try { + // call parseOBJGroup as long as it's returning true. Each successful call will + // add a new meshPart to the geometry's single mesh. while (parseOBJGroup(tokenizer, mapping, geometry)) { } diff --git a/tools/vhacd/src/VHACDUtilApp.cpp b/tools/vhacd/src/VHACDUtilApp.cpp index bea1b48206..958a91dbfe 100644 --- a/tools/vhacd/src/VHACDUtilApp.cpp +++ b/tools/vhacd/src/VHACDUtilApp.cpp @@ -143,25 +143,23 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) : //set parameters for V-HACD params.m_callback = &pCallBack; //progress callback - params.m_resolution = 100000; // 100000 - params.m_depth = 20; // 20 - params.m_concavity = 0.001; // 0.001 - params.m_delta = 0.01; // 0.05 - params.m_planeDownsampling = 4; // 4 - params.m_convexhullDownsampling = 4; // 4 - params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes - params.m_beta = 0.05; // 0.05 - params.m_gamma = 0.0005; // 0.0005 - params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition - params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based - params.m_maxNumVerticesPerCH = 64; // 64 - params.m_minVolumePerCH = 0.00001; // 0.0001 - params.m_callback = 0; // 0 - params.m_logger = 0; // 0 + params.m_resolution = 100000; // 100000 + params.m_depth = 20; // 20 + params.m_concavity = 0.001; // 0.001 + params.m_delta = 0.01; // 0.05 + params.m_planeDownsampling = 4; // 4 + params.m_convexhullDownsampling = 4; // 4 + params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes + params.m_beta = 0.05; // 0.05 + params.m_gamma = 0.0005; // 0.0005 + params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition + params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based + params.m_maxNumVerticesPerCH = 64; // 64 + params.m_minVolumePerCH = 0.00001; // 0.0001 + params.m_callback = 0; // 0 + params.m_logger = 0; // 0 params.m_convexhullApproximation = true; // true - params.m_oclAcceleration = true; // true - - + params.m_oclAcceleration = true; // true // load the mesh From ab8784f1b497b9eeb8521f1b422e85a94ef5b72f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 9 Mar 2015 13:51:08 -0700 Subject: [PATCH 39/43] add comment about character capsule being hard-coded --- libraries/fbx/src/OBJReader.cpp | 26 +++++++++++++++++++------ libraries/physics/src/PhysicsEngine.cpp | 1 + 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 194aaa4ac0..4f0f1246d2 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -121,18 +121,28 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeom break; } sawG = true; - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } QByteArray groupName = tokenizer.getDatum(); meshPart.materialID = groupName; } else if (token == "v") { - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } float x = std::stof(tokenizer.getDatum().data()); // notice the order of z and y -- in OBJ files, up is the 3rd value - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } float z = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } float y = std::stof(tokenizer.getDatum().data()); - if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } + if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { + break; + } // the spec gets vague here. might be w, might be a color... chop it off. tokenizer.skipLine(); mesh.vertices.append(glm::vec3(x, y, z)); @@ -199,10 +209,14 @@ FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) { geometry.meshExtents.reset(); geometry.meshes.append(FBXMesh()); + + try { // call parseOBJGroup as long as it's returning true. Each successful call will // add a new meshPart to the geometry's single mesh. - while (parseOBJGroup(tokenizer, mapping, geometry)) { + bool success = true; + while (success) { + success = parseOBJGroup(tokenizer, mapping, geometry); } FBXMesh &mesh = geometry.meshes[0]; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 501b39428a..6c5ac4b275 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -608,6 +608,7 @@ void PhysicsEngine::setAvatarData(AvatarData *avatarData) { _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); + // XXX these values should be computed from the character model. btScalar characterHeight = 1.75; btScalar characterWidth = 1.75; btScalar stepHeight = btScalar(0.35); From c947f3b62c096e690da161ef72c00fc136e68e2e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 9 Mar 2015 14:06:59 -0700 Subject: [PATCH 40/43] use meters in wire-protocol for versions greater than VERSION_ENTITIES_USE_METERS_AND_RADIANS --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 093f8cf84c..4f74438a45 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -501,7 +501,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef EntityPropertyFlags propertyFlags = encodedPropertyFlags; dataAt += propertyFlags.getEncodedLength(); bytesRead += propertyFlags.getEncodedLength(); - bool useMeters = (args.bitstreamVersion == VERSION_ENTITIES_USE_METERS_AND_RADIANS); + bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS); if (useMeters) { READ_ENTITY_PROPERTY_SETTER(PROP_POSITION, glm::vec3, updatePosition); } else { From 2a5d25e01007e63833612eefbbb4a8f11e4edc20 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 9 Mar 2015 16:02:07 -0700 Subject: [PATCH 41/43] more hacking on mixamo pipeline files --- interface/src/ModelUploader.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index f1c5def149..4093b3e610 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -332,8 +332,7 @@ void ModelUploader::populateBasicMapping(QVariantHash& mapping, QString filename // mixamo blendshapes - in the event that a mixamo file was edited by some other tool, it's likely the applicationName will // be rewritten, so we detect the existence of several different blendshapes which indicate we're likely a mixamo file bool likelyMixamoFile = geometry.applicationName == "mixamo.com" || - (geometry.blendshapeChannelNames.contains("Facial_Blends") && - geometry.blendshapeChannelNames.contains("BrowsDown_Right") && + (geometry.blendshapeChannelNames.contains("BrowsDown_Right") && geometry.blendshapeChannelNames.contains("MouthOpen") && geometry.blendshapeChannelNames.contains("Blink_Left") && geometry.blendshapeChannelNames.contains("Blink_Right") && From 3c05d685d726dccb9e64580e8ca542fb2bcc5a25 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 9 Mar 2015 17:37:34 -0700 Subject: [PATCH 42/43] avoid assert for zero-length character velocity --- libraries/physics/src/PhysicsEngine.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 6c5ac4b275..bd477a1c3c 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -290,8 +290,15 @@ void PhysicsEngine::stepSimulation() { if (_avatarData->isPhysicsEnabled()) { _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); - // _characterController->setWalkDirection(glmToBullet(_avatarData->getVelocity())); - _characterController->setVelocityForTimeInterval(glmToBullet(_avatarData->getVelocity()), timeStep); + // WORKAROUND: there is a bug in the debug Bullet-2.82 libs where a zero length walk velocity will trigger + // an assert when the getNormalizedVector() helper function in btKinematicCharacterController.cpp tries to + // first normalize a vector before checking its length. Here we workaround the problem by checking the + // length first. NOTE: the character's velocity is reset to zero after each step, so when we DON'T set + // the velocity for this time interval it is the same thing as setting its velocity to zero. + btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); + if (walkVelocity.length2() > FLT_EPSILON * FLT_EPSILON) { + _characterController->setVelocityForTimeInterval(walkVelocity, timeStep); + } } // This is step (2). From fd76eda383c45ea5590b125ee845c596b8be626e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 9 Mar 2015 17:59:45 -0700 Subject: [PATCH 43/43] slightly better hardcoded size for avatar capsule we'll be measuring avatar dimensions more correctly soon --- libraries/physics/src/PhysicsEngine.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index bd477a1c3c..66f8afb226 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -616,11 +616,11 @@ void PhysicsEngine::setAvatarData(AvatarData *avatarData) { glmToBullet(_avatarData->getPosition()))); // XXX these values should be computed from the character model. - btScalar characterHeight = 1.75; - btScalar characterWidth = 1.75; + btScalar characterRadius = 0.3; + btScalar characterHeight = 1.75 - 2.0f * characterRadius; btScalar stepHeight = btScalar(0.35); - btConvexShape* capsule = new btCapsuleShape(characterWidth, characterHeight); + btConvexShape* capsule = new btCapsuleShape(characterRadius, characterHeight); _avatarGhostObject->setCollisionShape(capsule); _avatarGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);