From 56b31ceaf55b9086e6ab8c07ca1143adbf65a64c Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Mon, 12 Feb 2024 07:52:47 -0800 Subject: [PATCH] add ignore list to raycasts --- CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwlua/nearbybindings.cpp | 69 +++++++-- apps/openmw/mwmechanics/aiwander.cpp | 2 +- .../closestnotmerayresultcallback.cpp | 2 +- .../closestnotmerayresultcallback.hpp | 8 +- apps/openmw/mwphysics/physicssystem.cpp | 26 ++-- apps/openmw/mwphysics/physicssystem.hpp | 9 +- apps/openmw/mwphysics/raycasting.hpp | 11 +- apps/openmw/mwrender/renderingmanager.cpp | 131 +++++++++++++++--- apps/openmw/mwrender/renderingmanager.hpp | 13 +- apps/openmw/mwworld/scene.cpp | 19 +-- apps/openmw/mwworld/scene.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 11 +- apps/openmw/mwworld/worldimp.hpp | 2 +- files/lua_api/openmw/nearby.lua | 7 + 16 files changed, 237 insertions(+), 79 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d62cda4f2b..7b1b18e41e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 49) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 53) +set(OPENMW_LUA_API_REVISION 54) set(OPENMW_POSTPROCESSING_API_REVISION 1) set(OPENMW_VERSION_COMMITHASH "") diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 4247ef2e3e..fe8b5cc13a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -304,7 +304,7 @@ namespace MWBase virtual const MWPhysics::RayCastingInterface* getRayCasting() const = 0; virtual bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to, - bool ignorePlayer, bool ignoreActors) + bool ignorePlayer, bool ignoreActors, std::span ignoreList = {}) = 0; virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0; diff --git a/apps/openmw/mwlua/nearbybindings.cpp b/apps/openmw/mwlua/nearbybindings.cpp index 7e1845aeac..7eda965e96 100644 --- a/apps/openmw/mwlua/nearbybindings.cpp +++ b/apps/openmw/mwlua/nearbybindings.cpp @@ -16,6 +16,31 @@ #include "luamanagerimp.hpp" #include "objectlists.hpp" +namespace +{ + template + std::vector parseIgnoreList(const sol::table& options) + { + std::vector ignore; + + if (const auto& ignoreObj = options.get>("ignore")) + { + ignore.push_back(ignoreObj->ptr()); + } + else if (const auto& ignoreTable = options.get>("ignore")) + { + ignoreTable->for_each([&](const auto& _, const sol::object& value) { + if (value.is()) + { + ignore.push_back(value.as().ptr()); + } + }); + } + + return ignore; + } +} + namespace sol { template <> @@ -71,24 +96,27 @@ namespace MWLua })); api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional options) { - MWWorld::Ptr ignore; + std::vector ignore; int collisionType = MWPhysics::CollisionType_Default; float radius = 0; if (options) { - sol::optional ignoreObj = options->get>("ignore"); - if (ignoreObj) - ignore = ignoreObj->ptr(); + ignore = parseIgnoreList(*options); collisionType = options->get>("collisionType").value_or(collisionType); radius = options->get>("radius").value_or(0); } const MWPhysics::RayCastingInterface* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting(); if (radius <= 0) - return rayCasting->castRay(from, to, ignore, std::vector(), collisionType); + { + return rayCasting->castRay(from, to, ignore, {}, collisionType); + } else { - if (!ignore.isEmpty()) - throw std::logic_error("Currently castRay doesn't support `ignore` when radius > 0"); + for (const auto& ptr : ignore) + { + if (!ptr.isEmpty()) + throw std::logic_error("Currently castRay doesn't support `ignore` when radius > 0"); + } return rayCasting->castSphere(from, to, radius, collisionType); } }; @@ -108,22 +136,37 @@ namespace MWLua // and use this callback from the main thread at the beginning of the next frame processing. rayCasting->asyncCastRay(callback, from, to, ignore, std::vector(), collisionType); };*/ - api["castRenderingRay"] = [manager = context.mLuaManager](const osg::Vec3f& from, const osg::Vec3f& to) { + api["castRenderingRay"] = [manager = context.mLuaManager](const osg::Vec3f& from, const osg::Vec3f& to, + const sol::optional& options) { if (!manager->isProcessingInputEvents()) { throw std::logic_error( "castRenderingRay can be used only in player scripts during processing of input events; " "use asyncCastRenderingRay instead."); } + + std::vector ignore; + if (options.has_value()) + { + ignore = parseIgnoreList(*options); + } + MWPhysics::RayCastingResult res; - MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false); + MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false, ignore); return res; }; - api["asyncCastRenderingRay"] = [context]( - const sol::table& callback, const osg::Vec3f& from, const osg::Vec3f& to) { - context.mLuaManager->addAction([context, callback = LuaUtil::Callback::fromLua(callback), from, to] { + api["asyncCastRenderingRay"] = [context](const sol::table& callback, const osg::Vec3f& from, + const osg::Vec3f& to, const sol::optional& options) { + std::vector ignore; + if (options.has_value()) + { + ignore = parseIgnoreList(*options); + } + + context.mLuaManager->addAction([context, ignore, callback = LuaUtil::Callback::fromLua(callback), from, + to] { MWPhysics::RayCastingResult res; - MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false); + MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false, ignore); context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res)); }); }; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index be2601dc37..38466c0c4c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -86,7 +86,7 @@ namespace MWMechanics return MWBase::Environment::get() .getWorld() ->getRayCasting() - ->castRay(position, visibleDestination, actor, {}, mask) + ->castRay(position, visibleDestination, { actor }, {}, mask) .mHit; } diff --git a/apps/openmw/mwphysics/closestnotmerayresultcallback.cpp b/apps/openmw/mwphysics/closestnotmerayresultcallback.cpp index 02c94a6f9d..b63cd568a8 100644 --- a/apps/openmw/mwphysics/closestnotmerayresultcallback.cpp +++ b/apps/openmw/mwphysics/closestnotmerayresultcallback.cpp @@ -12,7 +12,7 @@ namespace MWPhysics btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) { const auto* hitObject = rayResult.m_collisionObject; - if (hitObject == mMe) + if (std::find(mIgnoreList.begin(), mIgnoreList.end(), hitObject) != mIgnoreList.end()) return 1.f; if (hitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor && !mTargets.empty()) diff --git a/apps/openmw/mwphysics/closestnotmerayresultcallback.hpp b/apps/openmw/mwphysics/closestnotmerayresultcallback.hpp index f7f567ed4e..660f24424d 100644 --- a/apps/openmw/mwphysics/closestnotmerayresultcallback.hpp +++ b/apps/openmw/mwphysics/closestnotmerayresultcallback.hpp @@ -14,10 +14,10 @@ namespace MWPhysics class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { public: - explicit ClosestNotMeRayResultCallback(const btCollisionObject* me, std::span targets, - const btVector3& from, const btVector3& to) + explicit ClosestNotMeRayResultCallback(std::span ignore, + std::span targets, const btVector3& from, const btVector3& to) : btCollisionWorld::ClosestRayResultCallback(from, to) - , mMe(me) + , mIgnoreList(ignore) , mTargets(targets) { } @@ -25,7 +25,7 @@ namespace MWPhysics btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) override; private: - const btCollisionObject* mMe; + const std::span mIgnoreList; const std::span mTargets; }; } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 43888ac306..20a9c38b0f 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -192,7 +192,8 @@ namespace MWPhysics } RayCastingResult PhysicsSystem::castRay(const osg::Vec3f& from, const osg::Vec3f& to, - const MWWorld::ConstPtr& ignore, const std::vector& targets, int mask, int group) const + const std::vector& ignore, const std::vector& targets, int mask, + int group) const { if (from == to) { @@ -203,19 +204,22 @@ namespace MWPhysics btVector3 btFrom = Misc::Convert::toBullet(from); btVector3 btTo = Misc::Convert::toBullet(to); - const btCollisionObject* me = nullptr; + std::vector ignoreList; std::vector targetCollisionObjects; - if (!ignore.isEmpty()) + for (const auto& ptr : ignore) { - const Actor* actor = getActor(ignore); - if (actor) - me = actor->getCollisionObject(); - else + if (!ptr.isEmpty()) { - const Object* object = getObject(ignore); - if (object) - me = object->getCollisionObject(); + const Actor* actor = getActor(ptr); + if (actor) + ignoreList.push_back(actor->getCollisionObject()); + else + { + const Object* object = getObject(ptr); + if (object) + ignoreList.push_back(object->getCollisionObject()); + } } } @@ -229,7 +233,7 @@ namespace MWPhysics } } - ClosestNotMeRayResultCallback resultCallback(me, targetCollisionObjects, btFrom, btTo); + ClosestNotMeRayResultCallback resultCallback(ignoreList, targetCollisionObjects, btFrom, btTo); resultCallback.m_collisionFilterGroup = group; resultCallback.m_collisionFilterMask = mask; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 6734682092..9cc55fecc6 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -209,12 +209,11 @@ namespace MWPhysics const MWWorld::ConstPtr& ptr, int collisionGroup, int collisionMask) const; osg::Vec3f traceDown(const MWWorld::Ptr& ptr, const osg::Vec3f& position, float maxHeight); - /// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all - /// other actors. + /// @param ignore Optional, a list of Ptr to ignore in the list of results. targets are actors to filter for, + /// ignoring all other actors. RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to, - const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(), - const std::vector& targets = std::vector(), int mask = CollisionType_Default, - int group = 0xff) const override; + const std::vector& ignore = {}, const std::vector& targets = {}, + int mask = CollisionType_Default, int group = 0xff) const override; using RayCastingInterface::castRay; RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius, diff --git a/apps/openmw/mwphysics/raycasting.hpp b/apps/openmw/mwphysics/raycasting.hpp index 6b1a743d54..78b6ab4678 100644 --- a/apps/openmw/mwphysics/raycasting.hpp +++ b/apps/openmw/mwphysics/raycasting.hpp @@ -23,16 +23,15 @@ namespace MWPhysics public: virtual ~RayCastingInterface() = default; - /// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all - /// other actors. + /// @param ignore Optional, a list of Ptr to ignore in the list of results. targets are actors to filter for, + /// ignoring all other actors. virtual RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to, - const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(), - const std::vector& targets = std::vector(), int mask = CollisionType_Default, - int group = 0xff) const = 0; + const std::vector& ignore = {}, const std::vector& targets = {}, + int mask = CollisionType_Default, int group = 0xff) const = 0; RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask) const { - return castRay(from, to, MWWorld::ConstPtr(), std::vector(), mask); + return castRay(from, to, {}, {}, mask); } virtual RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius, diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 15faabb6df..224774d102 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -59,6 +59,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/groundcoverstore.hpp" +#include "../mwworld/scene.hpp" #include "../mwgui/postprocessorhud.hpp" @@ -1014,20 +1015,17 @@ namespace MWRender return osg::Vec4f(min_x, min_y, max_x, max_y); } - RenderingManager::RayResult getIntersectionResult(osgUtil::LineSegmentIntersector* intersector) + RenderingManager::RayResult getIntersectionResult(osgUtil::LineSegmentIntersector* intersector, + const osg::ref_ptr& visitor, std::span ignoreList = {}) { RenderingManager::RayResult result; result.mHit = false; result.mRatio = 0; - if (intersector->containsIntersections()) - { - result.mHit = true; - osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); - result.mHitPointWorld = intersection.getWorldIntersectPoint(); - result.mHitNormalWorld = intersection.getWorldIntersectNormal(); - result.mRatio = intersection.ratio; + if (!intersector->containsIntersections()) + return result; + auto test = [&](const osgUtil::LineSegmentIntersector::Intersection& intersection) { PtrHolder* ptrHolder = nullptr; std::vector refnumMarkers; for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); @@ -1039,9 +1037,16 @@ namespace MWRender for (unsigned int i = 0; i < userDataContainer->getNumUserObjects(); ++i) { if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) - ptrHolder = p; + { + if (std::find(ignoreList.begin(), ignoreList.end(), p->mPtr) == ignoreList.end()) + { + ptrHolder = p; + } + } if (RefnumMarker* r = dynamic_cast(userDataContainer->getUserObject(i))) + { refnumMarkers.push_back(r); + } } } @@ -1056,21 +1061,113 @@ namespace MWRender || (intersectionIndex >= vertexCounter && intersectionIndex < vertexCounter + refnumMarkers[i]->mNumVertices)) { - result.mHitRefnum = refnumMarkers[i]->mRefnum; + auto it = std::find_if( + ignoreList.begin(), ignoreList.end(), [target = refnumMarkers[i]->mRefnum](const auto& ptr) { + return target == ptr.getCellRef().getRefNum(); + }); + + if (it == ignoreList.end()) + { + result.mHitRefnum = refnumMarkers[i]->mRefnum; + } + break; } vertexCounter += refnumMarkers[i]->mNumVertices; } + + if (!result.mHitObject.isEmpty() || result.mHitRefnum.isSet()) + { + result.mHit = true; + result.mHitPointWorld = intersection.getWorldIntersectPoint(); + result.mHitNormalWorld = intersection.getWorldIntersectNormal(); + result.mRatio = intersection.ratio; + } + }; + + if (ignoreList.empty() || intersector->getIntersectionLimit() != osgUtil::LineSegmentIntersector::NO_LIMIT) + { + test(intersector->getFirstIntersection()); + } + else + { + for (const auto& intersection : intersector->getIntersections()) + { + test(intersection); + + if (result.mHit) + { + break; + } + } } return result; } + class IntersectionVisitorWithIgnoreList : public osgUtil::IntersectionVisitor + { + public: + bool skipTransform(osg::Transform& transform) + { + if (mContainsPagedRefs) + return false; + + osg::UserDataContainer* userDataContainer = transform.getUserDataContainer(); + if (!userDataContainer) + return false; + + for (unsigned int i = 0; i < userDataContainer->getNumUserObjects(); ++i) + { + if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) + { + if (std::find(mIgnoreList.begin(), mIgnoreList.end(), p->mPtr) != mIgnoreList.end()) + { + return true; + } + } + } + + return false; + } + + void apply(osg::Transform& transform) override + { + if (skipTransform(transform)) + { + return; + } + osgUtil::IntersectionVisitor::apply(transform); + } + + void setIgnoreList(std::span ignoreList) { mIgnoreList = ignoreList; } + void setContainsPagedRefs(bool contains) { mContainsPagedRefs = contains; } + + private: + std::span mIgnoreList; + bool mContainsPagedRefs = false; + }; + osg::ref_ptr RenderingManager::getIntersectionVisitor( - osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors) + osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors, + std::span ignoreList) { if (!mIntersectionVisitor) - mIntersectionVisitor = new osgUtil::IntersectionVisitor; + mIntersectionVisitor = new IntersectionVisitorWithIgnoreList; + + mIntersectionVisitor->setIgnoreList(ignoreList); + mIntersectionVisitor->setContainsPagedRefs(false); + + MWWorld::Scene* worldScene = MWBase::Environment::get().getWorldScene(); + for (const auto& ptr : ignoreList) + { + if (worldScene->isPagedRef(ptr)) + { + mIntersectionVisitor->setContainsPagedRefs(true); + intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT); + break; + } + } mIntersectionVisitor->setTraversalNumber(mViewer->getFrameStamp()->getFrameNumber()); mIntersectionVisitor->setFrameStamp(mViewer->getFrameStamp()); @@ -1088,16 +1185,16 @@ namespace MWRender return mIntersectionVisitor; } - RenderingManager::RayResult RenderingManager::castRay( - const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) + RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, + bool ignorePlayer, bool ignoreActors, std::span ignoreList) { osg::ref_ptr intersector( new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, origin, dest)); intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); - mRootNode->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); + mRootNode->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors, ignoreList)); - return getIntersectionResult(intersector); + return getIntersectionResult(intersector, mIntersectionVisitor, ignoreList); } RenderingManager::RayResult RenderingManager::castCameraToViewportRay( @@ -1117,7 +1214,7 @@ namespace MWRender mViewer->getCamera()->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); - return getIntersectionResult(intersector); + return getIntersectionResult(intersector, mIntersectionVisitor); } void RenderingManager::updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 22ef987c01..e138cc5b7d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MWRENDER_RENDERINGMANAGER_H #define OPENMW_MWRENDER_RENDERINGMANAGER_H +#include + #include #include #include @@ -87,6 +89,7 @@ namespace MWRender class StateUpdater; class SharedUniformStateUpdater; class PerViewUniformStateUpdater; + class IntersectionVisitorWithIgnoreList; class EffectManager; class ScreenshotManager; @@ -177,8 +180,8 @@ namespace MWRender float mRatio; }; - RayResult castRay( - const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors = false); + RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, + bool ignoreActors = false, std::span ignoreList = {}); /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen /// coordinates, where (0,0) is the top left corner. @@ -299,10 +302,10 @@ namespace MWRender const bool mSkyBlending; - osg::ref_ptr getIntersectionVisitor( - osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors); + osg::ref_ptr getIntersectionVisitor(osgUtil::Intersector* intersector, + bool ignorePlayer, bool ignoreActors, std::span ignoreList = {}); - osg::ref_ptr mIntersectionVisitor; + osg::ref_ptr mIntersectionVisitor; osg::ref_ptr mViewer; osg::ref_ptr mRootNode; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8424076758..a5787e301e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -99,6 +99,10 @@ namespace return ptr.getClass().getCorrectedModel(ptr); } + // Null node meant to distinguish objects that aren't in the scene from paged objects + // TODO: find a more clever way to make paging exclusion more reliable? + static osg::ref_ptr pagedNode = new SceneUtil::PositionAttitudeTransform; + void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const std::vector& pagedRefs, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { @@ -111,11 +115,6 @@ namespace std::string model = getModel(ptr); const auto rotation = makeDirectNodeRotation(ptr); - // Null node meant to distinguish objects that aren't in the scene from paged objects - // TODO: find a more clever way to make paging exclusion more reliable? - static const osg::ref_ptr pagedNode( - new SceneUtil::PositionAttitudeTransform); - ESM::RefNum refnum = ptr.getCellRef().getRefNum(); if (!refnum.hasContentFile() || !std::binary_search(pagedRefs.begin(), pagedRefs.end(), refnum)) ptr.getClass().insertObjectRendering(ptr, model, rendering); @@ -164,13 +163,13 @@ namespace Misc::Convert::makeBulletQuaternion(ptr.getCellRef().getPosition()), transform.getOrigin()); const auto start = Misc::Convert::toOsg(closedDoorTransform(center + toPoint)); - const auto startPoint = physics.castRay(start, start - osg::Vec3f(0, 0, 1000), ptr, {}, + const auto startPoint = physics.castRay(start, start - osg::Vec3f(0, 0, 1000), { ptr }, {}, MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Water); const auto connectionStart = startPoint.mHit ? startPoint.mHitPos : start; const auto end = Misc::Convert::toOsg(closedDoorTransform(center - toPoint)); - const auto endPoint = physics.castRay(end, end - osg::Vec3f(0, 0, 1000), ptr, {}, + const auto endPoint = physics.castRay(end, end - osg::Vec3f(0, 0, 1000), { ptr }, {}, MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Water); const auto connectionEnd = endPoint.mHit ? endPoint.mHitPos : end; @@ -274,7 +273,6 @@ namespace namespace MWWorld { - void Scene::removeFromPagedRefs(const Ptr& ptr) { ESM::RefNum refnum = ptr.getCellRef().getRefNum(); @@ -288,6 +286,11 @@ namespace MWWorld } } + bool Scene::isPagedRef(const Ptr& ptr) const + { + return ptr.getRefData().getBaseNode() == pagedNode.get(); + } + void Scene::updateObjectRotation(const Ptr& ptr, RotationOrder order) { const auto rot = makeNodeRotation(ptr, order); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index f3dd377845..fdca9bb87f 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -190,6 +190,8 @@ namespace MWWorld void removeFromPagedRefs(const Ptr& ptr); + bool isPagedRef(const Ptr& ptr) const; + void updateObjectRotation(const Ptr& ptr, RotationOrder order); void updateObjectScale(const Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 689edaf62e..e28efbf671 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1817,9 +1817,10 @@ namespace MWWorld } bool World::castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to, - bool ignorePlayer, bool ignoreActors) + bool ignorePlayer, bool ignoreActors, std::span ignoreList) { - MWRender::RenderingManager::RayResult rayRes = mRendering->castRay(from, to, ignorePlayer, ignoreActors); + MWRender::RenderingManager::RayResult rayRes + = mRendering->castRay(from, to, ignorePlayer, ignoreActors, ignoreList); res.mHit = rayRes.mHit; res.mHitPos = rayRes.mHitPointWorld; res.mHitNormal = rayRes.mHitNormalWorld; @@ -2598,7 +2599,7 @@ namespace MWWorld collisionTypes |= MWPhysics::CollisionType_Water; } MWPhysics::RayCastingResult result - = mPhysics->castRay(from, to, MWWorld::Ptr(), std::vector(), collisionTypes); + = mPhysics->castRay(from, to, { MWWorld::Ptr() }, std::vector(), collisionTypes); if (!result.mHit) return maxDist; @@ -3064,8 +3065,8 @@ namespace MWWorld actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors); // Check for impact, if yes, handle hit, if not, launch projectile - MWPhysics::RayCastingResult result - = mPhysics->castRay(sourcePos, worldPos, actor, targetActors, 0xff, MWPhysics::CollisionType_Projectile); + MWPhysics::RayCastingResult result = mPhysics->castRay( + sourcePos, worldPos, { actor }, targetActors, 0xff, MWPhysics::CollisionType_Projectile); if (result.mHit) MWMechanics::projectileHit(actor, result.mHitObject, bow, projectile, result.mHitPos, attackStrength); else diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b5d56753b0..4e36419e7f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -392,7 +392,7 @@ namespace MWWorld const MWPhysics::RayCastingInterface* getRayCasting() const override; bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to, - bool ignorePlayer, bool ignoreActors) override; + bool ignorePlayer, bool ignoreActors, std::span ignoreList) override; void setActorCollisionMode(const Ptr& ptr, bool internal, bool external) override; bool isActorCollisionEnabled(const Ptr& ptr) override; diff --git a/files/lua_api/openmw/nearby.lua b/files/lua_api/openmw/nearby.lua index 70b09efd90..ea1b8738bc 100644 --- a/files/lua_api/openmw/nearby.lua +++ b/files/lua_api/openmw/nearby.lua @@ -89,6 +89,11 @@ -- radius = 10, -- }) +--- +-- A table of parameters for @{#nearby.castRenderingRay} and @{#nearby.asyncCastRenderingRay} +-- @type CastRenderingRayOptions +-- @field #table ignore A list of @{openmw.core#GameObject} to ignore while doing the ray cast + --- -- Cast ray from one point to another and find the first visual intersection with anything in the scene. -- As opposite to `castRay` can find an intersection with an object without collisions. @@ -97,6 +102,7 @@ -- @function [parent=#nearby] castRenderingRay -- @param openmw.util#Vector3 from Start point of the ray. -- @param openmw.util#Vector3 to End point of the ray. +-- @param #CastRenderingRayOptions -- @return #RayCastingResult --- @@ -105,6 +111,7 @@ -- @param openmw.async#Callback callback The callback to pass the result to (should accept a single argument @{openmw.nearby#RayCastingResult}). -- @param openmw.util#Vector3 from Start point of the ray. -- @param openmw.util#Vector3 to End point of the ray. +-- @param #CastRenderingRayOptions --- -- @type NAVIGATOR_FLAGS