add ignore list to raycasts

BindlessTest
Cody Glassman 3 months ago
parent c889026b71
commit 56b31ceaf5

@ -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 "")

@ -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<const MWWorld::Ptr> ignoreList = {})
= 0;
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0;

@ -16,6 +16,31 @@
#include "luamanagerimp.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
{
template <>
@ -71,24 +96,27 @@ namespace MWLua
}));
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;
float radius = 0;
if (options)
{
sol::optional<LObject> ignoreObj = options->get<sol::optional<LObject>>("ignore");
if (ignoreObj)
ignore = ignoreObj->ptr();
ignore = parseIgnoreList<MWWorld::ConstPtr>(*options);
collisionType = options->get<sol::optional<int>>("collisionType").value_or(collisionType);
radius = options->get<sol::optional<float>>("radius").value_or(0);
}
const MWPhysics::RayCastingInterface* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting();
if (radius <= 0)
return rayCasting->castRay(from, to, ignore, std::vector<MWWorld::Ptr>(), 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<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())
{
throw std::logic_error(
"castRenderingRay can be used only in player scripts during processing of input events; "
"use asyncCastRenderingRay instead.");
}
std::vector<MWWorld::Ptr> 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<sol::table>& options) {
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;
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));
});
};

@ -86,7 +86,7 @@ namespace MWMechanics
return MWBase::Environment::get()
.getWorld()
->getRayCasting()
->castRay(position, visibleDestination, actor, {}, mask)
->castRay(position, visibleDestination, { actor }, {}, mask)
.mHit;
}

@ -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())

@ -14,10 +14,10 @@ namespace MWPhysics
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
{
public:
explicit ClosestNotMeRayResultCallback(const btCollisionObject* me, std::span<const btCollisionObject*> targets,
const btVector3& from, const btVector3& to)
explicit ClosestNotMeRayResultCallback(std::span<const btCollisionObject*> ignore,
std::span<const btCollisionObject*> 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<const btCollisionObject*> mIgnoreList;
const std::span<const btCollisionObject*> mTargets;
};
}

@ -192,7 +192,8 @@ namespace MWPhysics
}
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)
{
@ -203,19 +204,22 @@ namespace MWPhysics
btVector3 btFrom = Misc::Convert::toBullet(from);
btVector3 btTo = Misc::Convert::toBullet(to);
const btCollisionObject* me = nullptr;
std::vector<const btCollisionObject*> ignoreList;
std::vector<const btCollisionObject*> 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;

@ -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<MWWorld::Ptr>& targets = std::vector<MWWorld::Ptr>(), int mask = CollisionType_Default,
int group = 0xff) const override;
const std::vector<MWWorld::ConstPtr>& ignore = {}, const std::vector<MWWorld::Ptr>& 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,

@ -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<MWWorld::Ptr>& targets = std::vector<MWWorld::Ptr>(), int mask = CollisionType_Default,
int group = 0xff) const = 0;
const std::vector<MWWorld::ConstPtr>& ignore = {}, const std::vector<MWWorld::Ptr>& 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<MWWorld::Ptr>(), mask);
return castRay(from, to, {}, {}, mask);
}
virtual RayCastingResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius,

@ -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<osgUtil::IntersectionVisitor>& visitor, std::span<const MWWorld::Ptr> 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<RefnumMarker*> 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<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)))
{
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<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(
osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors)
osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors,
std::span<const MWWorld::Ptr> 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<const MWWorld::Ptr> ignoreList)
{
osg::ref_ptr<osgUtil::LineSegmentIntersector> 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)

@ -1,6 +1,8 @@
#ifndef OPENMW_MWRENDER_RENDERINGMANAGER_H
#define OPENMW_MWRENDER_RENDERINGMANAGER_H
#include <span>
#include <osg/Camera>
#include <osg/Light>
#include <osg/ref_ptr>
@ -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<const MWWorld::Ptr> 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<osgUtil::IntersectionVisitor> getIntersectionVisitor(
osgUtil::Intersector* intersector, bool ignorePlayer, bool ignoreActors);
osg::ref_ptr<osgUtil::IntersectionVisitor> getIntersectionVisitor(osgUtil::Intersector* intersector,
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<osg::Group> mRootNode;

@ -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<SceneUtil::PositionAttitudeTransform> pagedNode = new SceneUtil::PositionAttitudeTransform;
void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const std::vector<ESM::RefNum>& 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<SceneUtil::PositionAttitudeTransform> 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);

@ -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);

@ -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<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.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<MWWorld::Ptr>(), collisionTypes);
= mPhysics->castRay(from, to, { MWWorld::Ptr() }, std::vector<MWWorld::Ptr>(), 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

@ -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<const MWWorld::Ptr> ignoreList) override;
void setActorCollisionMode(const Ptr& ptr, bool internal, bool external) override;
bool isActorCollisionEnabled(const Ptr& ptr) override;

@ -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

Loading…
Cancel
Save