mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-01 09:09:42 +00:00
add ignore list to raycasts
This commit is contained in:
parent
c889026b71
commit
56b31ceaf5
16 changed files with 237 additions and 79 deletions
|
@ -72,7 +72,7 @@ message(STATUS "Configuring OpenMW...")
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 49)
|
set(OPENMW_VERSION_MINOR 49)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
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_POSTPROCESSING_API_REVISION 1)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
|
|
@ -304,7 +304,7 @@ namespace MWBase
|
||||||
virtual const MWPhysics::RayCastingInterface* getRayCasting() const = 0;
|
virtual const MWPhysics::RayCastingInterface* getRayCasting() const = 0;
|
||||||
|
|
||||||
virtual bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
|
virtual bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
|
||||||
bool ignorePlayer, bool ignoreActors)
|
bool ignorePlayer, bool ignoreActors, std::span<const MWWorld::Ptr> ignoreList = {})
|
||||||
= 0;
|
= 0;
|
||||||
|
|
||||||
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0;
|
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0;
|
||||||
|
|
|
@ -16,6 +16,31 @@
|
||||||
#include "luamanagerimp.hpp"
|
#include "luamanagerimp.hpp"
|
||||||
#include "objectlists.hpp"
|
#include "objectlists.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template <class T = MWWorld::Ptr>
|
||||||
|
std::vector<T> parseIgnoreList(const sol::table& options)
|
||||||
|
{
|
||||||
|
std::vector<T> ignore;
|
||||||
|
|
||||||
|
if (const auto& ignoreObj = options.get<sol::optional<MWLua::LObject>>("ignore"))
|
||||||
|
{
|
||||||
|
ignore.push_back(ignoreObj->ptr());
|
||||||
|
}
|
||||||
|
else if (const auto& ignoreTable = options.get<sol::optional<sol::table>>("ignore"))
|
||||||
|
{
|
||||||
|
ignoreTable->for_each([&](const auto& _, const sol::object& value) {
|
||||||
|
if (value.is<MWLua::LObject>())
|
||||||
|
{
|
||||||
|
ignore.push_back(value.as<MWLua::LObject>().ptr());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace sol
|
namespace sol
|
||||||
{
|
{
|
||||||
template <>
|
template <>
|
||||||
|
@ -71,24 +96,27 @@ namespace MWLua
|
||||||
}));
|
}));
|
||||||
|
|
||||||
api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options) {
|
api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options) {
|
||||||
MWWorld::Ptr ignore;
|
std::vector<MWWorld::ConstPtr> ignore;
|
||||||
int collisionType = MWPhysics::CollisionType_Default;
|
int collisionType = MWPhysics::CollisionType_Default;
|
||||||
float radius = 0;
|
float radius = 0;
|
||||||
if (options)
|
if (options)
|
||||||
{
|
{
|
||||||
sol::optional<LObject> ignoreObj = options->get<sol::optional<LObject>>("ignore");
|
ignore = parseIgnoreList<MWWorld::ConstPtr>(*options);
|
||||||
if (ignoreObj)
|
|
||||||
ignore = ignoreObj->ptr();
|
|
||||||
collisionType = options->get<sol::optional<int>>("collisionType").value_or(collisionType);
|
collisionType = options->get<sol::optional<int>>("collisionType").value_or(collisionType);
|
||||||
radius = options->get<sol::optional<float>>("radius").value_or(0);
|
radius = options->get<sol::optional<float>>("radius").value_or(0);
|
||||||
}
|
}
|
||||||
const MWPhysics::RayCastingInterface* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting();
|
const MWPhysics::RayCastingInterface* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting();
|
||||||
if (radius <= 0)
|
if (radius <= 0)
|
||||||
return rayCasting->castRay(from, to, ignore, std::vector<MWWorld::Ptr>(), collisionType);
|
{
|
||||||
|
return rayCasting->castRay(from, to, ignore, {}, collisionType);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ignore.isEmpty())
|
for (const auto& ptr : ignore)
|
||||||
throw std::logic_error("Currently castRay doesn't support `ignore` when radius > 0");
|
{
|
||||||
|
if (!ptr.isEmpty())
|
||||||
|
throw std::logic_error("Currently castRay doesn't support `ignore` when radius > 0");
|
||||||
|
}
|
||||||
return rayCasting->castSphere(from, to, radius, collisionType);
|
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.
|
// and use this callback from the main thread at the beginning of the next frame processing.
|
||||||
rayCasting->asyncCastRay(callback, from, to, ignore, std::vector<MWWorld::Ptr>(), collisionType);
|
rayCasting->asyncCastRay(callback, from, to, ignore, std::vector<MWWorld::Ptr>(), 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<sol::table>& options) {
|
||||||
if (!manager->isProcessingInputEvents())
|
if (!manager->isProcessingInputEvents())
|
||||||
{
|
{
|
||||||
throw std::logic_error(
|
throw std::logic_error(
|
||||||
"castRenderingRay can be used only in player scripts during processing of input events; "
|
"castRenderingRay can be used only in player scripts during processing of input events; "
|
||||||
"use asyncCastRenderingRay instead.");
|
"use asyncCastRenderingRay instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MWWorld::Ptr> ignore;
|
||||||
|
if (options.has_value())
|
||||||
|
{
|
||||||
|
ignore = parseIgnoreList(*options);
|
||||||
|
}
|
||||||
|
|
||||||
MWPhysics::RayCastingResult res;
|
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;
|
return res;
|
||||||
};
|
};
|
||||||
api["asyncCastRenderingRay"] = [context](
|
api["asyncCastRenderingRay"] = [context](const sol::table& callback, const osg::Vec3f& from,
|
||||||
const sol::table& callback, const osg::Vec3f& from, const osg::Vec3f& to) {
|
const osg::Vec3f& to, const sol::optional<sol::table>& options) {
|
||||||
context.mLuaManager->addAction([context, callback = LuaUtil::Callback::fromLua(callback), from, to] {
|
std::vector<MWWorld::Ptr> ignore;
|
||||||
|
if (options.has_value())
|
||||||
|
{
|
||||||
|
ignore = parseIgnoreList(*options);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.mLuaManager->addAction([context, ignore, callback = LuaUtil::Callback::fromLua(callback), from,
|
||||||
|
to] {
|
||||||
MWPhysics::RayCastingResult res;
|
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));
|
context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,7 +86,7 @@ namespace MWMechanics
|
||||||
return MWBase::Environment::get()
|
return MWBase::Environment::get()
|
||||||
.getWorld()
|
.getWorld()
|
||||||
->getRayCasting()
|
->getRayCasting()
|
||||||
->castRay(position, visibleDestination, actor, {}, mask)
|
->castRay(position, visibleDestination, { actor }, {}, mask)
|
||||||
.mHit;
|
.mHit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace MWPhysics
|
||||||
btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
|
btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
|
||||||
{
|
{
|
||||||
const auto* hitObject = rayResult.m_collisionObject;
|
const auto* hitObject = rayResult.m_collisionObject;
|
||||||
if (hitObject == mMe)
|
if (std::find(mIgnoreList.begin(), mIgnoreList.end(), hitObject) != mIgnoreList.end())
|
||||||
return 1.f;
|
return 1.f;
|
||||||
|
|
||||||
if (hitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor && !mTargets.empty())
|
if (hitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor && !mTargets.empty())
|
||||||
|
|
|
@ -14,10 +14,10 @@ namespace MWPhysics
|
||||||
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
|
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ClosestNotMeRayResultCallback(const btCollisionObject* me, std::span<const btCollisionObject*> targets,
|
explicit ClosestNotMeRayResultCallback(std::span<const btCollisionObject*> ignore,
|
||||||
const btVector3& from, const btVector3& to)
|
std::span<const btCollisionObject*> targets, const btVector3& from, const btVector3& to)
|
||||||
: btCollisionWorld::ClosestRayResultCallback(from, to)
|
: btCollisionWorld::ClosestRayResultCallback(from, to)
|
||||||
, mMe(me)
|
, mIgnoreList(ignore)
|
||||||
, mTargets(targets)
|
, mTargets(targets)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ namespace MWPhysics
|
||||||
btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) override;
|
btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const btCollisionObject* mMe;
|
const std::span<const btCollisionObject*> mIgnoreList;
|
||||||
const std::span<const btCollisionObject*> mTargets;
|
const std::span<const btCollisionObject*> mTargets;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,8 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
|
|
||||||
RayCastingResult PhysicsSystem::castRay(const osg::Vec3f& from, const osg::Vec3f& to,
|
RayCastingResult PhysicsSystem::castRay(const osg::Vec3f& from, const osg::Vec3f& to,
|
||||||
const MWWorld::ConstPtr& ignore, const std::vector<MWWorld::Ptr>& targets, int mask, int group) const
|
const std::vector<MWWorld::ConstPtr>& ignore, const std::vector<MWWorld::Ptr>& targets, int mask,
|
||||||
|
int group) const
|
||||||
{
|
{
|
||||||
if (from == to)
|
if (from == to)
|
||||||
{
|
{
|
||||||
|
@ -203,19 +204,22 @@ namespace MWPhysics
|
||||||
btVector3 btFrom = Misc::Convert::toBullet(from);
|
btVector3 btFrom = Misc::Convert::toBullet(from);
|
||||||
btVector3 btTo = Misc::Convert::toBullet(to);
|
btVector3 btTo = Misc::Convert::toBullet(to);
|
||||||
|
|
||||||
const btCollisionObject* me = nullptr;
|
std::vector<const btCollisionObject*> ignoreList;
|
||||||
std::vector<const btCollisionObject*> targetCollisionObjects;
|
std::vector<const btCollisionObject*> targetCollisionObjects;
|
||||||
|
|
||||||
if (!ignore.isEmpty())
|
for (const auto& ptr : ignore)
|
||||||
{
|
{
|
||||||
const Actor* actor = getActor(ignore);
|
if (!ptr.isEmpty())
|
||||||
if (actor)
|
|
||||||
me = actor->getCollisionObject();
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
const Object* object = getObject(ignore);
|
const Actor* actor = getActor(ptr);
|
||||||
if (object)
|
if (actor)
|
||||||
me = object->getCollisionObject();
|
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_collisionFilterGroup = group;
|
||||||
resultCallback.m_collisionFilterMask = mask;
|
resultCallback.m_collisionFilterMask = mask;
|
||||||
|
|
||||||
|
|
|
@ -209,12 +209,11 @@ namespace MWPhysics
|
||||||
const MWWorld::ConstPtr& ptr, int collisionGroup, int collisionMask) const;
|
const MWWorld::ConstPtr& ptr, int collisionGroup, int collisionMask) const;
|
||||||
osg::Vec3f traceDown(const MWWorld::Ptr& ptr, const osg::Vec3f& position, float maxHeight);
|
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
|
/// @param ignore Optional, a list of Ptr to ignore in the list of results. targets are actors to filter for,
|
||||||
/// other actors.
|
/// ignoring all other actors.
|
||||||
RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to,
|
RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to,
|
||||||
const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(),
|
const std::vector<MWWorld::ConstPtr>& ignore = {}, const std::vector<MWWorld::Ptr>& targets = {},
|
||||||
const std::vector<MWWorld::Ptr>& targets = std::vector<MWWorld::Ptr>(), int mask = CollisionType_Default,
|
int mask = CollisionType_Default, int group = 0xff) const override;
|
||||||
int group = 0xff) const override;
|
|
||||||
using RayCastingInterface::castRay;
|
using RayCastingInterface::castRay;
|
||||||
|
|
||||||
RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius,
|
RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius,
|
||||||
|
|
|
@ -23,16 +23,15 @@ namespace MWPhysics
|
||||||
public:
|
public:
|
||||||
virtual ~RayCastingInterface() = default;
|
virtual ~RayCastingInterface() = default;
|
||||||
|
|
||||||
/// @param me Optional, a Ptr to ignore in the list of results. targets are actors to filter for, ignoring all
|
/// @param ignore Optional, a list of Ptr to ignore in the list of results. targets are actors to filter for,
|
||||||
/// other actors.
|
/// ignoring all other actors.
|
||||||
virtual RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to,
|
virtual RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to,
|
||||||
const MWWorld::ConstPtr& ignore = MWWorld::ConstPtr(),
|
const std::vector<MWWorld::ConstPtr>& ignore = {}, const std::vector<MWWorld::Ptr>& targets = {},
|
||||||
const std::vector<MWWorld::Ptr>& targets = std::vector<MWWorld::Ptr>(), int mask = CollisionType_Default,
|
int mask = CollisionType_Default, int group = 0xff) const = 0;
|
||||||
int group = 0xff) const = 0;
|
|
||||||
|
|
||||||
RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask) const
|
RayCastingResult castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask) const
|
||||||
{
|
{
|
||||||
return castRay(from, to, MWWorld::ConstPtr(), std::vector<MWWorld::Ptr>(), mask);
|
return castRay(from, to, {}, {}, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius,
|
virtual RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius,
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/groundcoverstore.hpp"
|
#include "../mwworld/groundcoverstore.hpp"
|
||||||
|
#include "../mwworld/scene.hpp"
|
||||||
|
|
||||||
#include "../mwgui/postprocessorhud.hpp"
|
#include "../mwgui/postprocessorhud.hpp"
|
||||||
|
|
||||||
|
@ -1014,20 +1015,17 @@ namespace MWRender
|
||||||
return osg::Vec4f(min_x, min_y, max_x, max_y);
|
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<osgUtil::IntersectionVisitor>& visitor, std::span<const MWWorld::Ptr> ignoreList = {})
|
||||||
{
|
{
|
||||||
RenderingManager::RayResult result;
|
RenderingManager::RayResult result;
|
||||||
result.mHit = false;
|
result.mHit = false;
|
||||||
result.mRatio = 0;
|
result.mRatio = 0;
|
||||||
if (intersector->containsIntersections())
|
|
||||||
{
|
|
||||||
result.mHit = true;
|
|
||||||
osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection();
|
|
||||||
|
|
||||||
result.mHitPointWorld = intersection.getWorldIntersectPoint();
|
if (!intersector->containsIntersections())
|
||||||
result.mHitNormalWorld = intersection.getWorldIntersectNormal();
|
return result;
|
||||||
result.mRatio = intersection.ratio;
|
|
||||||
|
|
||||||
|
auto test = [&](const osgUtil::LineSegmentIntersector::Intersection& intersection) {
|
||||||
PtrHolder* ptrHolder = nullptr;
|
PtrHolder* ptrHolder = nullptr;
|
||||||
std::vector<RefnumMarker*> refnumMarkers;
|
std::vector<RefnumMarker*> refnumMarkers;
|
||||||
for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end();
|
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)
|
for (unsigned int i = 0; i < userDataContainer->getNumUserObjects(); ++i)
|
||||||
{
|
{
|
||||||
if (PtrHolder* p = dynamic_cast<PtrHolder*>(userDataContainer->getUserObject(i)))
|
if (PtrHolder* p = dynamic_cast<PtrHolder*>(userDataContainer->getUserObject(i)))
|
||||||
ptrHolder = p;
|
{
|
||||||
|
if (std::find(ignoreList.begin(), ignoreList.end(), p->mPtr) == ignoreList.end())
|
||||||
|
{
|
||||||
|
ptrHolder = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (RefnumMarker* r = dynamic_cast<RefnumMarker*>(userDataContainer->getUserObject(i)))
|
if (RefnumMarker* r = dynamic_cast<RefnumMarker*>(userDataContainer->getUserObject(i)))
|
||||||
|
{
|
||||||
refnumMarkers.push_back(r);
|
refnumMarkers.push_back(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,21 +1061,113 @@ namespace MWRender
|
||||||
|| (intersectionIndex >= vertexCounter
|
|| (intersectionIndex >= vertexCounter
|
||||||
&& intersectionIndex < vertexCounter + refnumMarkers[i]->mNumVertices))
|
&& 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;
|
break;
|
||||||
}
|
}
|
||||||
vertexCounter += refnumMarkers[i]->mNumVertices;
|
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;
|
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<PtrHolder*>(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<const MWWorld::Ptr> ignoreList) { mIgnoreList = ignoreList; }
|
||||||
|
void setContainsPagedRefs(bool contains) { mContainsPagedRefs = contains; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::span<const MWWorld::Ptr> mIgnoreList;
|
||||||
|
bool mContainsPagedRefs = false;
|
||||||
|
};
|
||||||
|
|
||||||
osg::ref_ptr<osgUtil::IntersectionVisitor> RenderingManager::getIntersectionVisitor(
|
osg::ref_ptr<osgUtil::IntersectionVisitor> RenderingManager::getIntersectionVisitor(
|
||||||
osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors)
|
osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors,
|
||||||
|
std::span<const MWWorld::Ptr> ignoreList)
|
||||||
{
|
{
|
||||||
if (!mIntersectionVisitor)
|
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->setTraversalNumber(mViewer->getFrameStamp()->getFrameNumber());
|
||||||
mIntersectionVisitor->setFrameStamp(mViewer->getFrameStamp());
|
mIntersectionVisitor->setFrameStamp(mViewer->getFrameStamp());
|
||||||
|
@ -1088,16 +1185,16 @@ namespace MWRender
|
||||||
return mIntersectionVisitor;
|
return mIntersectionVisitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderingManager::RayResult RenderingManager::castRay(
|
RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest,
|
||||||
const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors)
|
bool ignorePlayer, bool ignoreActors, std::span<const MWWorld::Ptr> ignoreList)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector(
|
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector(
|
||||||
new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, origin, dest));
|
new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, origin, dest));
|
||||||
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST);
|
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(
|
RenderingManager::RayResult RenderingManager::castCameraToViewportRay(
|
||||||
|
@ -1117,7 +1214,7 @@ namespace MWRender
|
||||||
|
|
||||||
mViewer->getCamera()->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors));
|
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)
|
void RenderingManager::updatePtr(const MWWorld::Ptr& old, const MWWorld::Ptr& updated)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef OPENMW_MWRENDER_RENDERINGMANAGER_H
|
#ifndef OPENMW_MWRENDER_RENDERINGMANAGER_H
|
||||||
#define OPENMW_MWRENDER_RENDERINGMANAGER_H
|
#define OPENMW_MWRENDER_RENDERINGMANAGER_H
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#include <osg/Camera>
|
#include <osg/Camera>
|
||||||
#include <osg/Light>
|
#include <osg/Light>
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
@ -87,6 +89,7 @@ namespace MWRender
|
||||||
class StateUpdater;
|
class StateUpdater;
|
||||||
class SharedUniformStateUpdater;
|
class SharedUniformStateUpdater;
|
||||||
class PerViewUniformStateUpdater;
|
class PerViewUniformStateUpdater;
|
||||||
|
class IntersectionVisitorWithIgnoreList;
|
||||||
|
|
||||||
class EffectManager;
|
class EffectManager;
|
||||||
class ScreenshotManager;
|
class ScreenshotManager;
|
||||||
|
@ -177,8 +180,8 @@ namespace MWRender
|
||||||
float mRatio;
|
float mRatio;
|
||||||
};
|
};
|
||||||
|
|
||||||
RayResult castRay(
|
RayResult castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer,
|
||||||
const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors = false);
|
bool ignoreActors = false, std::span<const MWWorld::Ptr> ignoreList = {});
|
||||||
|
|
||||||
/// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen
|
/// 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.
|
/// coordinates, where (0,0) is the top left corner.
|
||||||
|
@ -299,10 +302,10 @@ namespace MWRender
|
||||||
|
|
||||||
const bool mSkyBlending;
|
const bool mSkyBlending;
|
||||||
|
|
||||||
osg::ref_ptr<osgUtil::IntersectionVisitor> getIntersectionVisitor(
|
osg::ref_ptr<osgUtil::IntersectionVisitor> getIntersectionVisitor(osgUtil::Intersector* intersector,
|
||||||
osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors);
|
bool ignorePlayer, bool ignoreActors, std::span<const MWWorld::Ptr> ignoreList = {});
|
||||||
|
|
||||||
osg::ref_ptr<osgUtil::IntersectionVisitor> mIntersectionVisitor;
|
osg::ref_ptr<IntersectionVisitorWithIgnoreList> mIntersectionVisitor;
|
||||||
|
|
||||||
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
||||||
osg::ref_ptr<osg::Group> mRootNode;
|
osg::ref_ptr<osg::Group> mRootNode;
|
||||||
|
|
|
@ -99,6 +99,10 @@ namespace
|
||||||
return ptr.getClass().getCorrectedModel(ptr);
|
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<SceneUtil::PositionAttitudeTransform> pagedNode = new SceneUtil::PositionAttitudeTransform;
|
||||||
|
|
||||||
void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const std::vector<ESM::RefNum>& pagedRefs,
|
void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const std::vector<ESM::RefNum>& pagedRefs,
|
||||||
MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering)
|
MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering)
|
||||||
{
|
{
|
||||||
|
@ -111,11 +115,6 @@ namespace
|
||||||
std::string model = getModel(ptr);
|
std::string model = getModel(ptr);
|
||||||
const auto rotation = makeDirectNodeRotation(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<SceneUtil::PositionAttitudeTransform> pagedNode(
|
|
||||||
new SceneUtil::PositionAttitudeTransform);
|
|
||||||
|
|
||||||
ESM::RefNum refnum = ptr.getCellRef().getRefNum();
|
ESM::RefNum refnum = ptr.getCellRef().getRefNum();
|
||||||
if (!refnum.hasContentFile() || !std::binary_search(pagedRefs.begin(), pagedRefs.end(), refnum))
|
if (!refnum.hasContentFile() || !std::binary_search(pagedRefs.begin(), pagedRefs.end(), refnum))
|
||||||
ptr.getClass().insertObjectRendering(ptr, model, rendering);
|
ptr.getClass().insertObjectRendering(ptr, model, rendering);
|
||||||
|
@ -164,13 +163,13 @@ namespace
|
||||||
Misc::Convert::makeBulletQuaternion(ptr.getCellRef().getPosition()), transform.getOrigin());
|
Misc::Convert::makeBulletQuaternion(ptr.getCellRef().getPosition()), transform.getOrigin());
|
||||||
|
|
||||||
const auto start = Misc::Convert::toOsg(closedDoorTransform(center + toPoint));
|
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_World | MWPhysics::CollisionType_HeightMap
|
||||||
| MWPhysics::CollisionType_Water);
|
| MWPhysics::CollisionType_Water);
|
||||||
const auto connectionStart = startPoint.mHit ? startPoint.mHitPos : start;
|
const auto connectionStart = startPoint.mHit ? startPoint.mHitPos : start;
|
||||||
|
|
||||||
const auto end = Misc::Convert::toOsg(closedDoorTransform(center - toPoint));
|
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_World | MWPhysics::CollisionType_HeightMap
|
||||||
| MWPhysics::CollisionType_Water);
|
| MWPhysics::CollisionType_Water);
|
||||||
const auto connectionEnd = endPoint.mHit ? endPoint.mHitPos : end;
|
const auto connectionEnd = endPoint.mHit ? endPoint.mHitPos : end;
|
||||||
|
@ -274,7 +273,6 @@ namespace
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
void Scene::removeFromPagedRefs(const Ptr& ptr)
|
void Scene::removeFromPagedRefs(const Ptr& ptr)
|
||||||
{
|
{
|
||||||
ESM::RefNum refnum = ptr.getCellRef().getRefNum();
|
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)
|
void Scene::updateObjectRotation(const Ptr& ptr, RotationOrder order)
|
||||||
{
|
{
|
||||||
const auto rot = makeNodeRotation(ptr, order);
|
const auto rot = makeNodeRotation(ptr, order);
|
||||||
|
|
|
@ -190,6 +190,8 @@ namespace MWWorld
|
||||||
|
|
||||||
void removeFromPagedRefs(const Ptr& ptr);
|
void removeFromPagedRefs(const Ptr& ptr);
|
||||||
|
|
||||||
|
bool isPagedRef(const Ptr& ptr) const;
|
||||||
|
|
||||||
void updateObjectRotation(const Ptr& ptr, RotationOrder order);
|
void updateObjectRotation(const Ptr& ptr, RotationOrder order);
|
||||||
void updateObjectScale(const Ptr& ptr);
|
void updateObjectScale(const Ptr& ptr);
|
||||||
|
|
||||||
|
|
|
@ -1817,9 +1817,10 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
|
bool World::castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
|
||||||
bool ignorePlayer, bool ignoreActors)
|
bool ignorePlayer, bool ignoreActors, std::span<const MWWorld::Ptr> 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.mHit = rayRes.mHit;
|
||||||
res.mHitPos = rayRes.mHitPointWorld;
|
res.mHitPos = rayRes.mHitPointWorld;
|
||||||
res.mHitNormal = rayRes.mHitNormalWorld;
|
res.mHitNormal = rayRes.mHitNormalWorld;
|
||||||
|
@ -2598,7 +2599,7 @@ namespace MWWorld
|
||||||
collisionTypes |= MWPhysics::CollisionType_Water;
|
collisionTypes |= MWPhysics::CollisionType_Water;
|
||||||
}
|
}
|
||||||
MWPhysics::RayCastingResult result
|
MWPhysics::RayCastingResult result
|
||||||
= mPhysics->castRay(from, to, MWWorld::Ptr(), std::vector<MWWorld::Ptr>(), collisionTypes);
|
= mPhysics->castRay(from, to, { MWWorld::Ptr() }, std::vector<MWWorld::Ptr>(), collisionTypes);
|
||||||
|
|
||||||
if (!result.mHit)
|
if (!result.mHit)
|
||||||
return maxDist;
|
return maxDist;
|
||||||
|
@ -3064,8 +3065,8 @@ namespace MWWorld
|
||||||
actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors);
|
actor.getClass().getCreatureStats(actor).getAiSequence().getCombatTargets(targetActors);
|
||||||
|
|
||||||
// Check for impact, if yes, handle hit, if not, launch projectile
|
// Check for impact, if yes, handle hit, if not, launch projectile
|
||||||
MWPhysics::RayCastingResult result
|
MWPhysics::RayCastingResult result = mPhysics->castRay(
|
||||||
= mPhysics->castRay(sourcePos, worldPos, actor, targetActors, 0xff, MWPhysics::CollisionType_Projectile);
|
sourcePos, worldPos, { actor }, targetActors, 0xff, MWPhysics::CollisionType_Projectile);
|
||||||
if (result.mHit)
|
if (result.mHit)
|
||||||
MWMechanics::projectileHit(actor, result.mHitObject, bow, projectile, result.mHitPos, attackStrength);
|
MWMechanics::projectileHit(actor, result.mHitObject, bow, projectile, result.mHitPos, attackStrength);
|
||||||
else
|
else
|
||||||
|
|
|
@ -392,7 +392,7 @@ namespace MWWorld
|
||||||
const MWPhysics::RayCastingInterface* getRayCasting() const override;
|
const MWPhysics::RayCastingInterface* getRayCasting() const override;
|
||||||
|
|
||||||
bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
|
bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
|
||||||
bool ignorePlayer, bool ignoreActors) override;
|
bool ignorePlayer, bool ignoreActors, std::span<const MWWorld::Ptr> ignoreList) override;
|
||||||
|
|
||||||
void setActorCollisionMode(const Ptr& ptr, bool internal, bool external) override;
|
void setActorCollisionMode(const Ptr& ptr, bool internal, bool external) override;
|
||||||
bool isActorCollisionEnabled(const Ptr& ptr) override;
|
bool isActorCollisionEnabled(const Ptr& ptr) override;
|
||||||
|
|
|
@ -89,6 +89,11 @@
|
||||||
-- radius = 10,
|
-- 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.
|
-- 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.
|
-- As opposite to `castRay` can find an intersection with an object without collisions.
|
||||||
|
@ -97,6 +102,7 @@
|
||||||
-- @function [parent=#nearby] castRenderingRay
|
-- @function [parent=#nearby] castRenderingRay
|
||||||
-- @param openmw.util#Vector3 from Start point of the ray.
|
-- @param openmw.util#Vector3 from Start point of the ray.
|
||||||
-- @param openmw.util#Vector3 to End point of the ray.
|
-- @param openmw.util#Vector3 to End point of the ray.
|
||||||
|
-- @param #CastRenderingRayOptions
|
||||||
-- @return #RayCastingResult
|
-- @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.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 from Start point of the ray.
|
||||||
-- @param openmw.util#Vector3 to End point of the ray.
|
-- @param openmw.util#Vector3 to End point of the ray.
|
||||||
|
-- @param #CastRenderingRayOptions
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @type NAVIGATOR_FLAGS
|
-- @type NAVIGATOR_FLAGS
|
||||||
|
|
Loading…
Reference in a new issue