From 6e969ca3fae992a54aea6452a81caf32e8418135 Mon Sep 17 00:00:00 2001 From: fredzio Date: Fri, 5 Feb 2021 12:12:34 +0100 Subject: [PATCH] Use mesh collision box instead of node bounding sphere for projectile size. The bounding sphere is much bigger than the mesh. --- apps/openmw/mwphysics/physicssystem.cpp | 7 ++++++- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 22 +++++++++++++--------- apps/openmw/mwworld/projectilemanager.hpp | 2 +- components/resource/bulletshape.hpp | 2 +- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5a9a0be832..b434ff3406 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -682,9 +682,14 @@ namespace MWPhysics mActors.emplace(ptr, std::move(actor)); } - int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canTraverseWater) + int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater) { + osg::ref_ptr shapeInstance = mShapeManager->getInstance(mesh); + assert(shapeInstance); + float radius = computeRadius ? shapeInstance->mCollisionBox.extents.length() / 2.f : 1.f; + mProjectileId++; + auto projectile = std::make_shared(caster, position, radius, canTraverseWater, mTaskScheduler.get(), this); mProjectiles.emplace(mProjectileId, std::move(projectile)); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 715a6cd1a2..03d3020b9c 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -124,7 +124,7 @@ namespace MWPhysics void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, osg::Quat rotation, int collisionType = CollisionType_World); void addActor (const MWWorld::Ptr& ptr, const std::string& mesh); - int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canTraverseWater); + int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater); void updateProjectile(const int projectileId, const osg::Vec3f &position) const; void removeProjectile(const int projectileId); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 092ce270e9..3ffc7bb953 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -189,7 +189,7 @@ namespace MWWorld }; - float ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture) { state.mNode = new osg::PositionAttitudeTransform; @@ -253,7 +253,6 @@ namespace MWWorld state.mNode->accept(assignVisitor); MWRender::overrideFirstRootTexture(texture, mResourceSystem, projectile); - return projectile->getBound().radius(); } void ProjectileManager::update(State& state, float duration) @@ -308,7 +307,8 @@ namespace MWWorld osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects); - const auto radius = createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture); + auto model = ptr.getClass().getModel(ptr); + createModel(state, model, pos, orient, true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (const std::string &soundid : state.mSoundIds) @@ -319,7 +319,10 @@ namespace MWWorld state.mSounds.push_back(sound); } - state.mProjectileId = mPhysics->addProjectile(caster, pos, radius, false); + // in case there are multiple effects, the model is a dummy without geometry. Use the second effect for physics shape + if (state.mIdMagic.size() > 1) + model = "meshes\\" + MWBase::Environment::get().getWorld()->getStore().get().find(state.mIdMagic.at(1))->mModel; + state.mProjectileId = mPhysics->addProjectile(caster, pos, model, true, false); state.mToDelete = false; mMagicBolts.push_back(state); } @@ -339,11 +342,12 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false, osg::Vec4(0,0,0,0)); + const auto model = ptr.getClass().getModel(ptr); + createModel(state, model, pos, orient, false, false, osg::Vec4(0,0,0,0)); if (!ptr.getClass().getEnchantment(ptr).empty()) SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr)); - state.mProjectileId = mPhysics->addProjectile(actor, pos, 1.f, true); + state.mProjectileId = mPhysics->addProjectile(actor, pos, model, false, true); state.mToDelete = false; mProjectiles.push_back(state); } @@ -629,7 +633,7 @@ namespace MWWorld int weaponType = ptr.get()->mBase->mData.mType; state.mThrown = MWMechanics::getWeaponType(weaponType)->mWeaponClass == ESM::WeaponType::Thrown; - state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), 1.f, true); + state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, false, true); } catch(...) { @@ -681,8 +685,8 @@ namespace MWWorld } osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects); - const auto radius = createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture); - state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), radius, false); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture); + state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, true, false); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (const std::string &soundid : state.mSoundIds) diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index e088dd7011..c047d90ddf 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -130,7 +130,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - float createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture = ""); void update (State& state, float duration); diff --git a/components/resource/bulletshape.hpp b/components/resource/bulletshape.hpp index 7d9577ba02..8ad13fae14 100644 --- a/components/resource/bulletshape.hpp +++ b/components/resource/bulletshape.hpp @@ -32,7 +32,7 @@ namespace Resource osg::Vec3f extents; osg::Vec3f center; }; - // Used for actors. mCollisionShape is used for actors only when we need to autogenerate collision box for creatures. + // Used for actors and projectiles. mCollisionShape is used for actors only when we need to autogenerate collision box for creatures. // For now, use one file <-> one resource for simplicity. CollisionBox mCollisionBox;