mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 15:43:50 +02:00
Merge pull request #7821 from Atlante45/fix/collision-sound
Fix avatar/entity collision sound
This commit is contained in:
commit
2c0204b0d6
15 changed files with 92 additions and 43 deletions
|
@ -3013,8 +3013,19 @@ void Application::init() {
|
|||
_entityClipboardRenderer.setTree(_entityClipboard);
|
||||
|
||||
// Make sure any new sounds are loaded as soon as know about them.
|
||||
connect(tree.get(), &EntityTree::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
|
||||
connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
|
||||
connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) {
|
||||
EntityTreePointer tree = getEntities()->getTree();
|
||||
if (auto entity = tree->findEntityByEntityItemID(id)) {
|
||||
auto sound = DependencyManager::get<SoundCache>()->getSound(newURL);
|
||||
entity->setCollisionSound(sound);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) {
|
||||
if (auto avatar = getMyAvatar()) {
|
||||
auto sound = DependencyManager::get<SoundCache>()->getSound(newURL);
|
||||
avatar->setCollisionSound(sound);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void Application::updateLOD() const {
|
||||
|
|
|
@ -309,9 +309,11 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
|
|||
// my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.)
|
||||
if (collision.idA.isNull() || collision.idB.isNull()) {
|
||||
MyAvatar* myAvatar = getMyAvatar();
|
||||
const QString& collisionSoundURL = myAvatar->getCollisionSoundURL();
|
||||
if (!collisionSoundURL.isEmpty()) {
|
||||
const float velocityChange = glm::length(collision.velocityChange);
|
||||
auto collisionSound = myAvatar->getCollisionSound();
|
||||
if (collisionSound) {
|
||||
const auto characterController = myAvatar->getCharacterController();
|
||||
const float avatarVelocityChange = (characterController ? glm::length(characterController->getVelocityChange()) : 0.0f);
|
||||
const float velocityChange = glm::length(collision.velocityChange) + avatarVelocityChange;
|
||||
const float MIN_AVATAR_COLLISION_ACCELERATION = 0.01f;
|
||||
const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION);
|
||||
|
||||
|
@ -327,7 +329,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
|
|||
// but most avatars are roughly the same size, so let's not be so fancy yet.
|
||||
const float AVATAR_STRETCH_FACTOR = 1.0f;
|
||||
|
||||
AudioInjector::playSound(collisionSoundURL, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition());
|
||||
AudioInjector::playSound(collisionSound, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition());
|
||||
myAvatar->collisionWithEntity(collision);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <AudioClient.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
#include <FSTReader.h>
|
||||
#include <GeometryUtil.h>
|
||||
|
@ -32,6 +31,7 @@
|
|||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <SoundCache.h>
|
||||
#include <TextRenderer3D.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <AnimDebugDraw.h>
|
||||
|
@ -97,7 +97,6 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
||||
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
||||
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
||||
_collisionSoundURL(""),
|
||||
_characterController(this),
|
||||
_lookAtTargetAvatar(),
|
||||
_shouldRender(true),
|
||||
|
@ -1232,12 +1231,20 @@ void MyAvatar::clearScriptableSettings() {
|
|||
}
|
||||
|
||||
void MyAvatar::setCollisionSoundURL(const QString& url) {
|
||||
_collisionSoundURL = url;
|
||||
if (!url.isEmpty() && (url != _collisionSoundURL)) {
|
||||
emit newCollisionSoundURL(QUrl(url));
|
||||
if (url != _collisionSoundURL) {
|
||||
_collisionSoundURL = url;
|
||||
|
||||
emit newCollisionSoundURL(QUrl(_collisionSoundURL));
|
||||
}
|
||||
}
|
||||
|
||||
SharedSoundPointer MyAvatar::getCollisionSound() {
|
||||
if (!_collisionSound) {
|
||||
_collisionSound = DependencyManager::get<SoundCache>()->getSound(_collisionSoundURL);
|
||||
}
|
||||
return _collisionSound;
|
||||
}
|
||||
|
||||
void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
||||
const glm::vec3& translation, const glm::quat& rotation,
|
||||
float scale, bool isSoft,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <SettingHandle.h>
|
||||
#include <Rig.h>
|
||||
#include <Sound.h>
|
||||
|
||||
#include <controllers/Pose.h>
|
||||
|
||||
|
@ -222,6 +223,9 @@ public:
|
|||
const QString& getCollisionSoundURL() { return _collisionSoundURL; }
|
||||
void setCollisionSoundURL(const QString& url);
|
||||
|
||||
SharedSoundPointer getCollisionSound();
|
||||
void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; }
|
||||
|
||||
void clearScriptableSettings();
|
||||
|
||||
float getBoomLength() const { return _boomLength; }
|
||||
|
@ -362,6 +366,8 @@ private:
|
|||
quint32 _motionBehaviors;
|
||||
QString _collisionSoundURL;
|
||||
|
||||
SharedSoundPointer _collisionSound;
|
||||
|
||||
MyCharacterController _characterController;
|
||||
|
||||
AvatarWeakPointer _lookAtTargetAvatar;
|
||||
|
|
|
@ -365,17 +365,9 @@ void AudioInjector::stopAndDeleteLater() {
|
|||
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position) {
|
||||
if (soundUrl.isEmpty()) {
|
||||
return NULL;
|
||||
}
|
||||
auto soundCache = DependencyManager::get<SoundCache>();
|
||||
if (soundCache.isNull()) {
|
||||
return NULL;
|
||||
}
|
||||
SharedSoundPointer sound = soundCache->getSound(QUrl(soundUrl));
|
||||
if (sound.isNull() || !sound->isReady()) {
|
||||
return NULL;
|
||||
AudioInjector* AudioInjector::playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position) {
|
||||
if (!sound || !sound->isReady()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AudioInjectorOptions options;
|
||||
|
@ -385,7 +377,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
|
|||
|
||||
QByteArray samples = sound->getByteArray();
|
||||
if (stretchFactor == 1.0f) {
|
||||
return playSoundAndDelete(samples, options, NULL);
|
||||
return playSoundAndDelete(samples, options, nullptr);
|
||||
}
|
||||
|
||||
const int standardRate = AudioConstants::SAMPLE_RATE;
|
||||
|
@ -403,7 +395,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
|
|||
nInputFrames);
|
||||
|
||||
Q_UNUSED(nOutputFrames);
|
||||
return playSoundAndDelete(resampled, options, NULL);
|
||||
return playSoundAndDelete(resampled, options, nullptr);
|
||||
}
|
||||
|
||||
AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
|
||||
static AudioInjector* playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface);
|
||||
static AudioInjector* playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface);
|
||||
static AudioInjector* playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position);
|
||||
static AudioInjector* playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position);
|
||||
|
||||
public slots:
|
||||
void restart();
|
||||
|
|
|
@ -820,14 +820,14 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
|||
return;
|
||||
}
|
||||
|
||||
QString collisionSoundURL;
|
||||
SharedSoundPointer collisionSound;
|
||||
float mass = 1.0; // value doesn't get used, but set it so compiler is quiet
|
||||
AACube minAACube;
|
||||
bool success = false;
|
||||
_tree->withReadLock([&] {
|
||||
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
|
||||
if (entity) {
|
||||
collisionSoundURL = entity->getCollisionSoundURL();
|
||||
collisionSound = entity->getCollisionSound();
|
||||
mass = entity->computeMass();
|
||||
minAACube = entity->getMinimumAACube(success);
|
||||
}
|
||||
|
@ -835,9 +835,10 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
|||
if (!success) {
|
||||
return;
|
||||
}
|
||||
if (collisionSoundURL.isEmpty()) {
|
||||
if (!collisionSound) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity()
|
||||
// The collision.penetration is a pretty good indicator of changed velocity AFTER the initial contact,
|
||||
// but that first contact depends on exactly where we hit in the physics step.
|
||||
|
@ -859,11 +860,10 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
|||
const float COLLISION_SOUND_COMPRESSION_RANGE = 1.0f; // This section could be removed when the value is 1, but let's see how it goes.
|
||||
const float volume = (energyFactorOfFull * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE);
|
||||
|
||||
|
||||
// Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
|
||||
const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
|
||||
const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
|
||||
AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position);
|
||||
AudioInjector::playSound(collisionSound, volume, stretchFactor, position);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB,
|
||||
|
|
|
@ -852,6 +852,23 @@ void EntityItem::setHref(QString value) {
|
|||
_href = value;
|
||||
}
|
||||
|
||||
void EntityItem::setCollisionSoundURL(const QString& value) {
|
||||
if (_collisionSoundURL != value) {
|
||||
_collisionSoundURL = value;
|
||||
|
||||
if (auto myTree = getTree()) {
|
||||
myTree->notifyNewCollisionSoundURL(_collisionSoundURL, getEntityItemID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SharedSoundPointer EntityItem::getCollisionSound() {
|
||||
if (!_collisionSound) {
|
||||
_collisionSound = DependencyManager::get<SoundCache>()->getSound(_collisionSoundURL);
|
||||
}
|
||||
return _collisionSound;
|
||||
}
|
||||
|
||||
void EntityItem::simulate(const quint64& now) {
|
||||
if (_lastSimulated == 0) {
|
||||
_lastSimulated = now;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <PhysicsCollisionGroups.h>
|
||||
#include <ShapeInfo.h>
|
||||
#include <Transform.h>
|
||||
#include <Sound.h>
|
||||
#include <SpatiallyNestable.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
|
@ -250,7 +251,10 @@ public:
|
|||
void setScriptTimestamp(const quint64 value) { _scriptTimestamp = value; }
|
||||
|
||||
const QString& getCollisionSoundURL() const { return _collisionSoundURL; }
|
||||
void setCollisionSoundURL(const QString& value) { _collisionSoundURL = value; }
|
||||
void setCollisionSoundURL(const QString& value);
|
||||
|
||||
SharedSoundPointer getCollisionSound();
|
||||
void setCollisionSound(SharedSoundPointer sound) { _collisionSound = sound; }
|
||||
|
||||
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity
|
||||
|
||||
|
@ -478,6 +482,7 @@ protected:
|
|||
quint64 _loadedScriptTimestamp{ ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP + 1 };
|
||||
|
||||
QString _collisionSoundURL;
|
||||
SharedSoundPointer _collisionSound;
|
||||
glm::vec3 _registrationPoint;
|
||||
float _angularDamping;
|
||||
bool _visible;
|
||||
|
|
|
@ -95,7 +95,6 @@ void EntityTree::postAddEntity(EntityItemPointer entity) {
|
|||
}
|
||||
|
||||
_isDirty = true;
|
||||
maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL());
|
||||
emit addingEntity(entity->getEntityItemID());
|
||||
|
||||
// find and hook up any entities with this entity as a (previously) missing parent
|
||||
|
@ -223,7 +222,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
|
||||
QString entityScriptBefore = entity->getScript();
|
||||
quint64 entityScriptTimestampBefore = entity->getScriptTimestamp();
|
||||
QString collisionSoundURLBefore = entity->getCollisionSoundURL();
|
||||
uint32_t preFlags = entity->getDirtyFlags();
|
||||
|
||||
AACube newQueryAACube;
|
||||
|
@ -295,7 +293,6 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
if (entityScriptBefore != entityScriptAfter || reload) {
|
||||
emitEntityScriptChanging(entity->getEntityItemID(), reload); // the entity script has changed
|
||||
}
|
||||
maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL());
|
||||
}
|
||||
|
||||
// TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG).
|
||||
|
@ -362,10 +359,8 @@ void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID, cons
|
|||
emit entityScriptChanging(entityItemID, reload);
|
||||
}
|
||||
|
||||
void EntityTree::maybeNotifyNewCollisionSoundURL(const QString& previousCollisionSoundURL, const QString& nextCollisionSoundURL) {
|
||||
if (!nextCollisionSoundURL.isEmpty() && (nextCollisionSoundURL != previousCollisionSoundURL)) {
|
||||
emit newCollisionSoundURL(QUrl(nextCollisionSoundURL));
|
||||
}
|
||||
void EntityTree::notifyNewCollisionSoundURL(const QString& newURL, const EntityItemID& entityID) {
|
||||
emit newCollisionSoundURL(QUrl(newURL), entityID);
|
||||
}
|
||||
|
||||
void EntityTree::setSimulation(EntitySimulation* simulation) {
|
||||
|
|
|
@ -249,6 +249,8 @@ public:
|
|||
void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; }
|
||||
void deleteDescendantsOfAvatar(QUuid avatarID);
|
||||
|
||||
void notifyNewCollisionSoundURL(const QString& newCollisionSoundURL, const EntityItemID& entityID);
|
||||
|
||||
public slots:
|
||||
void callLoader(EntityItemID entityID);
|
||||
|
||||
|
@ -256,7 +258,7 @@ signals:
|
|||
void deletingEntity(const EntityItemID& entityID);
|
||||
void addingEntity(const EntityItemID& entityID);
|
||||
void entityScriptChanging(const EntityItemID& entityItemID, const bool reload);
|
||||
void newCollisionSoundURL(const QUrl& url);
|
||||
void newCollisionSoundURL(const QUrl& url, const EntityItemID& entityID);
|
||||
void clearingEntities();
|
||||
|
||||
protected:
|
||||
|
@ -301,7 +303,6 @@ protected:
|
|||
|
||||
bool _wantEditLogging = false;
|
||||
bool _wantTerseEditLogging = false;
|
||||
void maybeNotifyNewCollisionSoundURL(const QString& oldCollisionSoundURL, const QString& newCollisionSoundURL);
|
||||
|
||||
|
||||
// some performance tracking properties - only used in server trees
|
||||
|
|
|
@ -34,8 +34,6 @@ OctreeElementPointer EntityTreeElement::createNewElement(unsigned char* octalCod
|
|||
return newChild;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EntityTreeElement::init(unsigned char* octalCode) {
|
||||
OctreeElement::init(octalCode);
|
||||
_octreeMemoryUsage += sizeof(EntityTreeElement);
|
||||
|
|
|
@ -430,6 +430,14 @@ glm::vec3 CharacterController::getLinearVelocity() const {
|
|||
return velocity;
|
||||
}
|
||||
|
||||
glm::vec3 CharacterController::getVelocityChange() const {
|
||||
glm::vec3 velocity(0.0f);
|
||||
if (_rigidBody) {
|
||||
velocity = bulletToGLM(_rigidBody->getLinearVelocity());
|
||||
}
|
||||
return velocity;
|
||||
}
|
||||
|
||||
void CharacterController::preSimulation() {
|
||||
if (_enabled && _dynamicsWorld) {
|
||||
quint64 now = usecTimestampNow();
|
||||
|
@ -437,6 +445,7 @@ void CharacterController::preSimulation() {
|
|||
// slam body to where it is supposed to be
|
||||
_rigidBody->setWorldTransform(_characterBodyTransform);
|
||||
btVector3 velocity = _rigidBody->getLinearVelocity();
|
||||
_preSimulationVelocity = velocity;
|
||||
|
||||
btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp;
|
||||
btVector3 actualHorizVelocity = velocity - actualVertVelocity;
|
||||
|
@ -531,6 +540,9 @@ void CharacterController::preSimulation() {
|
|||
|
||||
void CharacterController::postSimulation() {
|
||||
// postSimulation() exists for symmetry and just in case we need to do something here later
|
||||
|
||||
btVector3 velocity = _rigidBody->getLinearVelocity();
|
||||
_velocityChange = velocity - _preSimulationVelocity;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
glm::vec3 getFollowVelocity() const;
|
||||
|
||||
glm::vec3 getLinearVelocity() const;
|
||||
glm::vec3 getVelocityChange() const;
|
||||
|
||||
float getCapsuleRadius() const { return _radius; }
|
||||
float getCapsuleHalfHeight() const { return _halfHeight; }
|
||||
|
@ -112,6 +113,8 @@ protected:
|
|||
btVector3 _currentUp;
|
||||
btVector3 _targetVelocity;
|
||||
btVector3 _parentVelocity;
|
||||
btVector3 _preSimulationVelocity;
|
||||
btVector3 _velocityChange;
|
||||
btTransform _followDesiredBodyTransform;
|
||||
btScalar _followTimeRemaining;
|
||||
btTransform _characterBodyTransform;
|
||||
|
|
|
@ -7,6 +7,6 @@ setup_hifi_project(Network Script)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation)
|
||||
link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation audio)
|
||||
|
||||
package_libraries_for_deployment()
|
||||
|
|
Loading…
Reference in a new issue