diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 688ce70345..871bcbf76c 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -99,9 +99,6 @@ void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) { VoxelDetail* voxelDetails = NULL; if (_voxels->findSpherePenetration(center, radius, collisionInfo._penetration, (void**)&voxelDetails)) { - // let the Entities run their collision scripts if they have them - //entity->collisionWithVoxel(voxelDetails, collisionInfo._penetration); - // findSpherePenetration() only computes the penetration but we also want some other collision info // so we compute it ourselves here. Note that we must multiply scale by TREE_SCALE when feeding // the results to systems outside of this octree reference frame. @@ -112,9 +109,8 @@ void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) { // we must scale back down to the octree reference frame before updating the Entity properties collisionInfo._penetration /= (float)(TREE_SCALE); collisionInfo._contactPoint /= (float)(TREE_SCALE); - entity->applyHardCollision(collisionInfo); - queueEntityPropertiesUpdate(entity); + applyHardCollision(entity, collisionInfo); delete voxelDetails; // cleanup returned details } } @@ -138,9 +134,6 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { if (doCollisions) { quint64 now = usecTimestampNow(); - entityA->collisionWithEntity(entityB, penetration); - entityB->collisionWithEntity(entityA, penetration * -1.0f); // the penetration is reversed - CollisionInfo collision; collision._penetration = penetration; // for now the contactPoint is the average between the the two paricle centers @@ -188,9 +181,6 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) { - // TODO: implement support for colliding with avatars - -#if 0 // Entities that are in hand, don't collide with avatars if (!_avatars) { return; @@ -200,7 +190,6 @@ void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) { float radius = entity->getRadius() * (float)(TREE_SCALE); const float ELASTICITY = 0.9f; const float DAMPING = 0.1f; - const float COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; _collisions.clear(); @@ -227,22 +216,57 @@ void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) { // only collide when Entity and collision point are moving toward each other // (doing this prevents some "collision snagging" when Entity penetrates the object) collision->_penetration /= (float)(TREE_SCALE); - entity->applyHardCollision(*collision); - queueEntityPropertiesUpdate(entity); + applyHardCollision(entity, *collision); } } } } - -#endif } -void EntityCollisionSystem::queueEntityPropertiesUpdate(EntityItem* entity) { - // queue the result for sending to the Entity server +void EntityCollisionSystem::applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo) { + // HALTING_* params are determined using expected acceleration of gravity over some timescale. + // This is a HACK for entities that bounce in a 1.0 gravitational field and should eventually be made more universal. + const float HALTING_ENTITY_PERIOD = 0.0167f; // ~1/60th of a second + const float HALTING_ENTITY_SPEED = 9.8 * HALTING_ENTITY_PERIOD / (float)(TREE_SCALE); + + // + // Update the entity in response to a hard collision. Position will be reset exactly + // to outside the colliding surface. Velocity will be modified according to elasticity. + // + // if elasticity = 0.0, collision is inelastic (vel normal to collision is lost) + // if elasticity = 1.0, collision is 100% elastic. + // + glm::vec3 position = entity->getPosition(); + glm::vec3 velocity = entity->getVelocity(); + + const float EPSILON = 0.0f; + glm::vec3 relativeVelocity = collisionInfo._addedVelocity - velocity; + float velocityDotPenetration = glm::dot(relativeVelocity, collisionInfo._penetration); + if (velocityDotPenetration < EPSILON) { + // entity is moving into collision surface + // + // TODO: do something smarter here by comparing the mass of the entity vs that of the other thing + // (other's mass could be stored in the Collision Info). The smaller mass should surrender more + // position offset and should slave more to the other's velocity in the static-friction case. + position -= collisionInfo._penetration; + + if (glm::length(relativeVelocity) < HALTING_ENTITY_SPEED) { + // static friction kicks in and entities moves with colliding object + velocity = collisionInfo._addedVelocity; + } else { + glm::vec3 direction = glm::normalize(collisionInfo._penetration); + velocity += glm::dot(relativeVelocity, direction) * (1.0f + collisionInfo._elasticity) * direction; // dynamic reflection + velocity += glm::clamp(collisionInfo._damping, 0.0f, 1.0f) * (relativeVelocity - glm::dot(relativeVelocity, direction) * direction); // dynamic friction + } + } + EntityItemProperties properties = entity->getProperties(); EntityItemID entityItemID(entity->getID()); - properties.setPosition(entity->getPosition() * (float)TREE_SCALE); - properties.setVelocity(entity->getVelocity() * (float)TREE_SCALE); + properties.setPosition(position * (float)TREE_SCALE); + properties.setVelocity(velocity * (float)TREE_SCALE); + properties.setLastEdited(usecTimestampNow()); + + _entities->updateEntity(entityItemID, properties); _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, entityItemID, properties); } diff --git a/libraries/entities/src/EntityCollisionSystem.h b/libraries/entities/src/EntityCollisionSystem.h index fe38209c09..b2cf7a9df4 100644 --- a/libraries/entities/src/EntityCollisionSystem.h +++ b/libraries/entities/src/EntityCollisionSystem.h @@ -58,6 +58,8 @@ signals: void EntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& penetration); private: + void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo); + static bool updateOperation(OctreeElement* element, void* extraData); void emitGlobalEntityCollisionWithVoxel(EntityItem* Entity, VoxelDetail* voxelDetails, const CollisionInfo& penetration); void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const CollisionInfo& penetration); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8a0a92c6a5..cfed16c443 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -903,76 +903,3 @@ float EntityItem::getRadius() const { return radius; } -void EntityItem::applyHardCollision(const CollisionInfo& collisionInfo) { - // HALTING_* params are determined using expected acceleration of gravity over some timescale. - // This is a HACK for entities that bounce in a 1.0 gravitational field and should eventually be made more universal. - const float HALTING_ENTITY_PERIOD = 0.0167f; // ~1/60th of a second - const float HALTING_ENTITY_SPEED = 9.8 * HALTING_ENTITY_PERIOD / (float)(TREE_SCALE); - - // - // Update the entity in response to a hard collision. Position will be reset exactly - // to outside the colliding surface. Velocity will be modified according to elasticity. - // - // if elasticity = 0.0, collision is inelastic (vel normal to collision is lost) - // if elasticity = 1.0, collision is 100% elastic. - // - glm::vec3 position = getPosition(); - glm::vec3 velocity = getVelocity(); - - const float EPSILON = 0.0f; - glm::vec3 relativeVelocity = collisionInfo._addedVelocity - velocity; - float velocityDotPenetration = glm::dot(relativeVelocity, collisionInfo._penetration); - if (velocityDotPenetration < EPSILON) { - // entity is moving into collision surface - // - // TODO: do something smarter here by comparing the mass of the entity vs that of the other thing - // (other's mass could be stored in the Collision Info). The smaller mass should surrender more - // position offset and should slave more to the other's velocity in the static-friction case. - position -= collisionInfo._penetration; - - if (glm::length(relativeVelocity) < HALTING_ENTITY_SPEED) { - // static friction kicks in and entities moves with colliding object - velocity = collisionInfo._addedVelocity; - } else { - glm::vec3 direction = glm::normalize(collisionInfo._penetration); - velocity += glm::dot(relativeVelocity, direction) * (1.0f + collisionInfo._elasticity) * direction; // dynamic reflection - velocity += glm::clamp(collisionInfo._damping, 0.0f, 1.0f) * (relativeVelocity - glm::dot(relativeVelocity, direction) * direction); // dynamic friction - } - } - - // TODO: how do we handle fixing up the location in the octree cells? - // change the local entity too... - setPosition(position); - setVelocity(velocity); -} - -void EntityItem::collisionWithEntity(EntityItem* other, const glm::vec3& penetration) { - // TODO: how do we want to handle collision related scripts for entities? - /* - // Only run this particle script if there's a script attached directly to the entity. - if (!_script.isEmpty()) { - ScriptEngine engine(_script); - ParticleScriptObject particleScriptable(this); - startParticleScriptContext(engine, particleScriptable); - ParticleScriptObject otherParticleScriptable(other); - particleScriptable.emitCollisionWithParticle(&otherParticleScriptable, penetration); - endParticleScriptContext(engine, particleScriptable); - } - */ -} - -void EntityItem::collisionWithVoxel(VoxelDetail* voxelDetails, const glm::vec3& penetration) { - // TODO: how do we want to handle collision related scripts for entities? - /* - // Only run this entity script if there's a script attached directly to the entity. - if (!_script.isEmpty()) { - ScriptEngine engine(_script); - ParticleScriptObject particleScriptable(this); - startParticleScriptContext(engine, particleScriptable); - particleScriptable.emitCollisionWithVoxel(*voxelDetails, penetration); - endParticleScriptContext(engine, particleScriptable); - } - */ -} - - diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7b03c786ed..bbfba30e9c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -229,8 +229,6 @@ public: float getRadius() const; void applyHardCollision(const CollisionInfo& collisionInfo); - void collisionWithEntity(EntityItem* other, const glm::vec3& penetration); - void collisionWithVoxel(VoxelDetail* voxelDetails, const glm::vec3& penetration); protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init diff --git a/libraries/voxels/src/VoxelDetail.h b/libraries/voxels/src/VoxelDetail.h index 50a60828e7..b94601392b 100644 --- a/libraries/voxels/src/VoxelDetail.h +++ b/libraries/voxels/src/VoxelDetail.h @@ -51,4 +51,19 @@ Q_DECLARE_METATYPE(RayToVoxelIntersectionResult) QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& results); void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, RayToVoxelIntersectionResult& results); + +inline QDebug operator<<(QDebug debug, const VoxelDetail& details) { + const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of the 0.0 to 1.0 voxel universe + + debug << "VoxelDetail[ (" + << details.x * (float)TREE_SCALE << "," << details.y * (float)TREE_SCALE << "," << details.z * (float)TREE_SCALE + << " ) to (" + << details.x + details.s * (float)TREE_SCALE << "," << details.y + details.s * (float)TREE_SCALE + << "," << details.z + details.s * (float)TREE_SCALE << ") size: (" + << details.s * (float)TREE_SCALE << "," << details.s * (float)TREE_SCALE << "," << details.s * (float)TREE_SCALE << ")" + << " in meters]"; + + return debug; +} + #endif // hifi_VoxelDetail_h diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index 4907298a3c..5143c04918 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -5,6 +5,6 @@ setup_hifi_project(Script Network) include_glm() # link in the shared libraries -link_hifi_libraries(animation avatars fbx entities networking octree shared voxels) +link_hifi_libraries(shared octree voxels fbx metavoxels networking particles entities avatars audio animation script-engine) link_shared_dependencies()