mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 02:36:54 +02:00
give MyAvatar a VoxelShapeManager member
This commit is contained in:
parent
83e04a0e8f
commit
2c1aa31d1e
2 changed files with 119 additions and 100 deletions
|
@ -79,7 +79,8 @@ MyAvatar::MyAvatar() :
|
||||||
_lookAtTargetAvatar(),
|
_lookAtTargetAvatar(),
|
||||||
_shouldRender(true),
|
_shouldRender(true),
|
||||||
_billboardValid(false),
|
_billboardValid(false),
|
||||||
_physicsSimulation()
|
_physicsSimulation(),
|
||||||
|
_voxelShapeManager()
|
||||||
{
|
{
|
||||||
ShapeCollider::initDispatchTable();
|
ShapeCollider::initDispatchTable();
|
||||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||||
|
@ -90,11 +91,11 @@ MyAvatar::MyAvatar() :
|
||||||
_skeletonModel.setEnableShapes(true);
|
_skeletonModel.setEnableShapes(true);
|
||||||
Ragdoll* ragdoll = _skeletonModel.buildRagdoll();
|
Ragdoll* ragdoll = _skeletonModel.buildRagdoll();
|
||||||
_physicsSimulation.setRagdoll(ragdoll);
|
_physicsSimulation.setRagdoll(ragdoll);
|
||||||
|
_physicsSimulation.addEntity(&_voxelShapeManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
MyAvatar::~MyAvatar() {
|
MyAvatar::~MyAvatar() {
|
||||||
_physicsSimulation.setRagdoll(NULL);
|
_physicsSimulation.clear();
|
||||||
_physicsSimulation.setEntity(NULL);
|
|
||||||
_lookAtTargetAvatar.clear();
|
_lookAtTargetAvatar.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1486,112 +1487,125 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
|
||||||
static CollisionList myCollisions(64);
|
static CollisionList myCollisions(64);
|
||||||
|
|
||||||
void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) {
|
void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) {
|
||||||
const float MAX_VOXEL_COLLISION_SPEED = 100.0f;
|
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
|
||||||
float speed = glm::length(_velocity);
|
// compute the bounding cube around avatar
|
||||||
if (speed > MAX_VOXEL_COLLISION_SPEED) {
|
float radius = 2.0f * getBoundingRadius();
|
||||||
// don't even bother to try to collide against voxles when moving very fast
|
glm::vec3 corner = getPosition() - glm::vec3(radius);
|
||||||
_trapDuration = 0.0f;
|
AACube boundingCube(corner, 2.0f * radius);
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool isTrapped = false;
|
|
||||||
myCollisions.clear();
|
|
||||||
const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
|
|
||||||
if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions, Octree::TryLock)) {
|
|
||||||
const float VOXEL_ELASTICITY = 0.0f;
|
|
||||||
const float VOXEL_DAMPING = 0.0f;
|
|
||||||
float capsuleRadius = boundingShape.getRadius();
|
|
||||||
float capsuleHalfHeight = boundingShape.getHalfHeight();
|
|
||||||
const float MAX_STEP_HEIGHT = capsuleRadius + capsuleHalfHeight;
|
|
||||||
const float MIN_STEP_HEIGHT = 0.0f;
|
|
||||||
glm::vec3 footBase = boundingShape.getTranslation() - (capsuleRadius + capsuleHalfHeight) * _worldUpDirection;
|
|
||||||
float highestStep = 0.0f;
|
|
||||||
float lowestStep = MAX_STEP_HEIGHT;
|
|
||||||
glm::vec3 floorPoint;
|
|
||||||
glm::vec3 stepPenetration(0.0f);
|
|
||||||
glm::vec3 totalPenetration(0.0f);
|
|
||||||
|
|
||||||
for (int i = 0; i < myCollisions.size(); ++i) {
|
// query the VoxelTree for cubes that touch avatar's boundingCube
|
||||||
CollisionInfo* collision = myCollisions[i];
|
CubeList cubes;
|
||||||
glm::vec3 cubeCenter = collision->_vecData;
|
if (Application::getInstance()->getVoxelTree()->findContentInCube(boundingCube, cubes)) {
|
||||||
float cubeSide = collision->_floatData;
|
_voxelShapeManager.updateVoxels(cubes);
|
||||||
float verticalDepth = glm::dot(collision->_penetration, _worldUpDirection);
|
|
||||||
float horizontalDepth = glm::length(collision->_penetration - verticalDepth * _worldUpDirection);
|
|
||||||
const float MAX_TRAP_PERIOD = 0.125f;
|
|
||||||
if (horizontalDepth > capsuleRadius || fabsf(verticalDepth) > MAX_STEP_HEIGHT) {
|
|
||||||
isTrapped = true;
|
|
||||||
if (_trapDuration > MAX_TRAP_PERIOD) {
|
|
||||||
float distance = glm::dot(boundingShape.getTranslation() - cubeCenter, _worldUpDirection);
|
|
||||||
if (distance < 0.0f) {
|
|
||||||
distance = fabsf(distance) + 0.5f * cubeSide;
|
|
||||||
}
|
|
||||||
distance += capsuleRadius + capsuleHalfHeight;
|
|
||||||
totalPenetration = addPenetrations(totalPenetration, - distance * _worldUpDirection);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (_trapDuration > MAX_TRAP_PERIOD) {
|
|
||||||
// we're trapped, ignore this collision
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
|
|
||||||
if (glm::dot(collision->_penetration, _velocity) >= 0.0f) {
|
|
||||||
glm::vec3 cubeTop = cubeCenter + (0.5f * cubeSide) * _worldUpDirection;
|
|
||||||
float stepHeight = glm::dot(_worldUpDirection, cubeTop - footBase);
|
|
||||||
if (stepHeight > highestStep) {
|
|
||||||
highestStep = stepHeight;
|
|
||||||
stepPenetration = collision->_penetration;
|
|
||||||
}
|
|
||||||
if (stepHeight < lowestStep) {
|
|
||||||
lowestStep = stepHeight;
|
|
||||||
floorPoint = collision->_contactPoint - collision->_penetration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (lowestStep < MAX_STEP_HEIGHT) {
|
} else {
|
||||||
_lastFloorContactPoint = floorPoint;
|
const float MAX_VOXEL_COLLISION_SPEED = 100.0f;
|
||||||
}
|
float speed = glm::length(_velocity);
|
||||||
|
if (speed > MAX_VOXEL_COLLISION_SPEED) {
|
||||||
float penetrationLength = glm::length(totalPenetration);
|
// don't even bother to try to collide against voxles when moving very fast
|
||||||
if (penetrationLength < EPSILON) {
|
|
||||||
_trapDuration = 0.0f;
|
_trapDuration = 0.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float verticalPenetration = glm::dot(totalPenetration, _worldUpDirection);
|
bool isTrapped = false;
|
||||||
if (highestStep > MIN_STEP_HEIGHT && highestStep < MAX_STEP_HEIGHT && verticalPenetration <= 0.0f) {
|
myCollisions.clear();
|
||||||
// we're colliding against an edge
|
const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
|
||||||
glm::vec3 targetVelocity = _motorVelocity;
|
if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions, Octree::TryLock)) {
|
||||||
if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) {
|
const float VOXEL_ELASTICITY = 0.0f;
|
||||||
// rotate _motorVelocity into world frame
|
const float VOXEL_DAMPING = 0.0f;
|
||||||
glm::quat rotation = getHead()->getCameraOrientation();
|
float capsuleRadius = boundingShape.getRadius();
|
||||||
targetVelocity = rotation * _motorVelocity;
|
float capsuleHalfHeight = boundingShape.getHalfHeight();
|
||||||
}
|
const float MAX_STEP_HEIGHT = capsuleRadius + capsuleHalfHeight;
|
||||||
if (_wasPushing && glm::dot(targetVelocity, totalPenetration) > EPSILON) {
|
const float MIN_STEP_HEIGHT = 0.0f;
|
||||||
// we're puhing into the edge, so we want to lift
|
glm::vec3 footBase = boundingShape.getTranslation() - (capsuleRadius + capsuleHalfHeight) * _worldUpDirection;
|
||||||
|
float highestStep = 0.0f;
|
||||||
// remove unhelpful horizontal component of the step's penetration
|
float lowestStep = MAX_STEP_HEIGHT;
|
||||||
totalPenetration -= stepPenetration - (glm::dot(stepPenetration, _worldUpDirection) * _worldUpDirection);
|
glm::vec3 floorPoint;
|
||||||
|
glm::vec3 stepPenetration(0.0f);
|
||||||
// further adjust penetration to help lift
|
glm::vec3 totalPenetration(0.0f);
|
||||||
float liftSpeed = glm::max(MAX_WALKING_SPEED, speed);
|
|
||||||
float thisStep = glm::min(liftSpeed * deltaTime, highestStep);
|
for (int i = 0; i < myCollisions.size(); ++i) {
|
||||||
float extraStep = glm::dot(totalPenetration, _worldUpDirection) + thisStep;
|
CollisionInfo* collision = myCollisions[i];
|
||||||
if (extraStep > 0.0f) {
|
glm::vec3 cubeCenter = collision->_vecData;
|
||||||
totalPenetration -= extraStep * _worldUpDirection;
|
float cubeSide = collision->_floatData;
|
||||||
|
float verticalDepth = glm::dot(collision->_penetration, _worldUpDirection);
|
||||||
|
float horizontalDepth = glm::length(collision->_penetration - verticalDepth * _worldUpDirection);
|
||||||
|
const float MAX_TRAP_PERIOD = 0.125f;
|
||||||
|
if (horizontalDepth > capsuleRadius || fabsf(verticalDepth) > MAX_STEP_HEIGHT) {
|
||||||
|
isTrapped = true;
|
||||||
|
if (_trapDuration > MAX_TRAP_PERIOD) {
|
||||||
|
float distance = glm::dot(boundingShape.getTranslation() - cubeCenter, _worldUpDirection);
|
||||||
|
if (distance < 0.0f) {
|
||||||
|
distance = fabsf(distance) + 0.5f * cubeSide;
|
||||||
|
}
|
||||||
|
distance += capsuleRadius + capsuleHalfHeight;
|
||||||
|
totalPenetration = addPenetrations(totalPenetration, - distance * _worldUpDirection);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (_trapDuration > MAX_TRAP_PERIOD) {
|
||||||
|
// we're trapped, ignore this collision
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
|
||||||
|
if (glm::dot(collision->_penetration, _velocity) >= 0.0f) {
|
||||||
|
glm::vec3 cubeTop = cubeCenter + (0.5f * cubeSide) * _worldUpDirection;
|
||||||
|
float stepHeight = glm::dot(_worldUpDirection, cubeTop - footBase);
|
||||||
|
if (stepHeight > highestStep) {
|
||||||
|
highestStep = stepHeight;
|
||||||
|
stepPenetration = collision->_penetration;
|
||||||
|
}
|
||||||
|
if (stepHeight < lowestStep) {
|
||||||
|
lowestStep = stepHeight;
|
||||||
|
floorPoint = collision->_contactPoint - collision->_penetration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lowestStep < MAX_STEP_HEIGHT) {
|
||||||
|
_lastFloorContactPoint = floorPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
float penetrationLength = glm::length(totalPenetration);
|
||||||
|
if (penetrationLength < EPSILON) {
|
||||||
|
_trapDuration = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float verticalPenetration = glm::dot(totalPenetration, _worldUpDirection);
|
||||||
|
if (highestStep > MIN_STEP_HEIGHT && highestStep < MAX_STEP_HEIGHT && verticalPenetration <= 0.0f) {
|
||||||
|
// we're colliding against an edge
|
||||||
|
glm::vec3 targetVelocity = _motorVelocity;
|
||||||
|
if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) {
|
||||||
|
// rotate _motorVelocity into world frame
|
||||||
|
glm::quat rotation = getHead()->getCameraOrientation();
|
||||||
|
targetVelocity = rotation * _motorVelocity;
|
||||||
|
}
|
||||||
|
if (_wasPushing && glm::dot(targetVelocity, totalPenetration) > EPSILON) {
|
||||||
|
// we're puhing into the edge, so we want to lift
|
||||||
|
|
||||||
|
// remove unhelpful horizontal component of the step's penetration
|
||||||
|
totalPenetration -= stepPenetration - (glm::dot(stepPenetration, _worldUpDirection) * _worldUpDirection);
|
||||||
|
|
||||||
|
// further adjust penetration to help lift
|
||||||
|
float liftSpeed = glm::max(MAX_WALKING_SPEED, speed);
|
||||||
|
float thisStep = glm::min(liftSpeed * deltaTime, highestStep);
|
||||||
|
float extraStep = glm::dot(totalPenetration, _worldUpDirection) + thisStep;
|
||||||
|
if (extraStep > 0.0f) {
|
||||||
|
totalPenetration -= extraStep * _worldUpDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
_position -= totalPenetration;
|
||||||
|
} else {
|
||||||
|
// we're not pushing into the edge, so let the avatar fall
|
||||||
|
applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
|
||||||
}
|
}
|
||||||
|
|
||||||
_position -= totalPenetration;
|
|
||||||
} else {
|
} else {
|
||||||
// we're not pushing into the edge, so let the avatar fall
|
|
||||||
applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
|
applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
|
// Don't make a collision sound against voxlels by default -- too annoying when walking
|
||||||
}
|
//const float VOXEL_COLLISION_FREQUENCY = 0.5f;
|
||||||
|
//updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY);
|
||||||
// Don't make a collision sound against voxlels by default -- too annoying when walking
|
}
|
||||||
//const float VOXEL_COLLISION_FREQUENCY = 0.5f;
|
_trapDuration = isTrapped ? _trapDuration + deltaTime : 0.0f;
|
||||||
//updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY);
|
}
|
||||||
}
|
|
||||||
_trapDuration = isTrapped ? _trapDuration + deltaTime : 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) {
|
void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) {
|
||||||
|
@ -1952,6 +1966,9 @@ void MyAvatar::updateMotionBehaviorsFromMenu() {
|
||||||
} else {
|
} else {
|
||||||
_motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
|
_motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
|
||||||
}
|
}
|
||||||
|
if (!(_collisionGroups | COLLISION_GROUP_VOXELS)) {
|
||||||
|
_voxelShapeManager.clearShapes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::renderAttachments(RenderMode renderMode) {
|
void MyAvatar::renderAttachments(RenderMode renderMode) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <PhysicsSimulation.h>
|
#include <PhysicsSimulation.h>
|
||||||
|
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
|
#include "VoxelShapeManager.h"
|
||||||
|
|
||||||
class ModelItemID;
|
class ModelItemID;
|
||||||
|
|
||||||
|
@ -214,6 +215,7 @@ private:
|
||||||
|
|
||||||
QList<AnimationHandlePointer> _animationHandles;
|
QList<AnimationHandlePointer> _animationHandles;
|
||||||
PhysicsSimulation _physicsSimulation;
|
PhysicsSimulation _physicsSimulation;
|
||||||
|
VoxelShapeManager _voxelShapeManager;
|
||||||
|
|
||||||
RecorderPointer _recorder;
|
RecorderPointer _recorder;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue