mirror of
https://github.com/overte-org/overte.git
synced 2025-07-17 11:36:43 +02:00
collions with voxels and avatars
This commit is contained in:
parent
6b8c9bba42
commit
4b52fddffd
6 changed files with 62 additions and 96 deletions
|
@ -99,9 +99,6 @@ void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) {
|
||||||
VoxelDetail* voxelDetails = NULL;
|
VoxelDetail* voxelDetails = NULL;
|
||||||
if (_voxels->findSpherePenetration(center, radius, collisionInfo._penetration, (void**)&voxelDetails)) {
|
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
|
// 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
|
// 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.
|
// 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
|
// we must scale back down to the octree reference frame before updating the Entity properties
|
||||||
collisionInfo._penetration /= (float)(TREE_SCALE);
|
collisionInfo._penetration /= (float)(TREE_SCALE);
|
||||||
collisionInfo._contactPoint /= (float)(TREE_SCALE);
|
collisionInfo._contactPoint /= (float)(TREE_SCALE);
|
||||||
entity->applyHardCollision(collisionInfo);
|
|
||||||
queueEntityPropertiesUpdate(entity);
|
|
||||||
|
|
||||||
|
applyHardCollision(entity, collisionInfo);
|
||||||
delete voxelDetails; // cleanup returned details
|
delete voxelDetails; // cleanup returned details
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,9 +134,6 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) {
|
||||||
if (doCollisions) {
|
if (doCollisions) {
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
entityA->collisionWithEntity(entityB, penetration);
|
|
||||||
entityB->collisionWithEntity(entityA, penetration * -1.0f); // the penetration is reversed
|
|
||||||
|
|
||||||
CollisionInfo collision;
|
CollisionInfo collision;
|
||||||
collision._penetration = penetration;
|
collision._penetration = penetration;
|
||||||
// for now the contactPoint is the average between the the two paricle centers
|
// 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) {
|
void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) {
|
||||||
|
|
||||||
// TODO: implement support for colliding with avatars
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// Entities that are in hand, don't collide with avatars
|
// Entities that are in hand, don't collide with avatars
|
||||||
if (!_avatars) {
|
if (!_avatars) {
|
||||||
return;
|
return;
|
||||||
|
@ -200,7 +190,6 @@ void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) {
|
||||||
float radius = entity->getRadius() * (float)(TREE_SCALE);
|
float radius = entity->getRadius() * (float)(TREE_SCALE);
|
||||||
const float ELASTICITY = 0.9f;
|
const float ELASTICITY = 0.9f;
|
||||||
const float DAMPING = 0.1f;
|
const float DAMPING = 0.1f;
|
||||||
const float COLLISION_FREQUENCY = 0.5f;
|
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
|
|
||||||
_collisions.clear();
|
_collisions.clear();
|
||||||
|
@ -227,22 +216,57 @@ void EntityCollisionSystem::updateCollisionWithAvatars(EntityItem* entity) {
|
||||||
// only collide when Entity and collision point are moving toward each other
|
// only collide when Entity and collision point are moving toward each other
|
||||||
// (doing this prevents some "collision snagging" when Entity penetrates the object)
|
// (doing this prevents some "collision snagging" when Entity penetrates the object)
|
||||||
collision->_penetration /= (float)(TREE_SCALE);
|
collision->_penetration /= (float)(TREE_SCALE);
|
||||||
entity->applyHardCollision(*collision);
|
applyHardCollision(entity, *collision);
|
||||||
queueEntityPropertiesUpdate(entity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityCollisionSystem::queueEntityPropertiesUpdate(EntityItem* entity) {
|
void EntityCollisionSystem::applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo) {
|
||||||
// queue the result for sending to the Entity server
|
// 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();
|
EntityItemProperties properties = entity->getProperties();
|
||||||
EntityItemID entityItemID(entity->getID());
|
EntityItemID entityItemID(entity->getID());
|
||||||
|
|
||||||
properties.setPosition(entity->getPosition() * (float)TREE_SCALE);
|
properties.setPosition(position * (float)TREE_SCALE);
|
||||||
properties.setVelocity(entity->getVelocity() * (float)TREE_SCALE);
|
properties.setVelocity(velocity * (float)TREE_SCALE);
|
||||||
|
properties.setLastEdited(usecTimestampNow());
|
||||||
|
|
||||||
|
_entities->updateEntity(entityItemID, properties);
|
||||||
_packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, entityItemID, properties);
|
_packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, entityItemID, properties);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,8 @@ signals:
|
||||||
void EntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& penetration);
|
void EntityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& penetration);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo);
|
||||||
|
|
||||||
static bool updateOperation(OctreeElement* element, void* extraData);
|
static bool updateOperation(OctreeElement* element, void* extraData);
|
||||||
void emitGlobalEntityCollisionWithVoxel(EntityItem* Entity, VoxelDetail* voxelDetails, const CollisionInfo& penetration);
|
void emitGlobalEntityCollisionWithVoxel(EntityItem* Entity, VoxelDetail* voxelDetails, const CollisionInfo& penetration);
|
||||||
void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const CollisionInfo& penetration);
|
void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const CollisionInfo& penetration);
|
||||||
|
|
|
@ -903,76 +903,3 @@ float EntityItem::getRadius() const {
|
||||||
return radius;
|
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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -229,8 +229,6 @@ public:
|
||||||
float getRadius() const;
|
float getRadius() const;
|
||||||
|
|
||||||
void applyHardCollision(const CollisionInfo& collisionInfo);
|
void applyHardCollision(const CollisionInfo& collisionInfo);
|
||||||
void collisionWithEntity(EntityItem* other, const glm::vec3& penetration);
|
|
||||||
void collisionWithVoxel(VoxelDetail* voxelDetails, const glm::vec3& penetration);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||||
|
|
|
@ -51,4 +51,19 @@ Q_DECLARE_METATYPE(RayToVoxelIntersectionResult)
|
||||||
QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& results);
|
QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& results);
|
||||||
void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, 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
|
#endif // hifi_VoxelDetail_h
|
||||||
|
|
|
@ -5,6 +5,6 @@ setup_hifi_project(Script Network)
|
||||||
include_glm()
|
include_glm()
|
||||||
|
|
||||||
# link in the shared libraries
|
# 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()
|
link_shared_dependencies()
|
||||||
|
|
Loading…
Reference in a new issue