1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-31 06:32:39 +00:00

Rendering raycasts in Lua

This commit is contained in:
Petr Mikheev 2022-03-18 00:27:16 +01:00
parent a65f8ebbc6
commit 51845e9553
9 changed files with 77 additions and 6 deletions

View File

@ -57,6 +57,7 @@ namespace ESM
namespace MWPhysics
{
class RayCastingResult;
class RayCastingInterface;
}
@ -331,6 +332,9 @@ namespace MWBase
virtual bool castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask, const MWWorld::ConstPtr& ignore) = 0;
virtual bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
bool ignorePlayer, bool ignoreActors) = 0;
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0;
virtual bool isActorCollisionEnabled(const MWWorld::Ptr& ptr) = 0;

View File

@ -41,7 +41,7 @@ namespace MWLua
{
auto* lua = context.mLua;
sol::table api(lua->sol(), sol::create);
api["API_REVISION"] = 20;
api["API_REVISION"] = 21;
api["quit"] = [lua]()
{
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();

View File

@ -226,6 +226,7 @@ namespace MWLua
return; // The game is not started yet.
// We apply input events in `synchronizedUpdate` rather than in `update` in order to reduce input latency.
mProcessingInputEvents = true;
PlayerScripts* playerScripts = dynamic_cast<PlayerScripts*>(mPlayer.getRefData().getLuaScripts());
if (playerScripts && !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu))
{
@ -235,6 +236,7 @@ namespace MWLua
mInputEvents.clear();
if (playerScripts && !mWorldView.isPaused())
playerScripts->inputUpdate(MWBase::Environment::get().getFrameDuration());
mProcessingInputEvents = false;
MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager();
for (const std::string& message : mUIMessages)

View File

@ -111,12 +111,15 @@ namespace MWLua
LuaUi::ResourceManager* uiResourceManager() { return &mUiResourceManager; }
bool isProcessingInputEvents() const { return mProcessingInputEvents; }
private:
void initConfiguration();
LocalScripts* createLocalScripts(const MWWorld::Ptr& ptr, ESM::LuaScriptCfg::Flags);
bool mInitialized = false;
bool mGlobalScriptsStarted = false;
bool mProcessingInputEvents = false;
LuaUtil::ScriptsConfiguration mConfiguration;
LuaUtil::LuaState mLua;
LuaUi::ResourceManager mUiResourceManager;

View File

@ -6,6 +6,7 @@
#include "../mwbase/world.hpp"
#include "../mwphysics/raycasting.hpp"
#include "luamanagerimp.hpp"
#include "worldview.hpp"
namespace sol
@ -91,6 +92,27 @@ 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)
{
if (!manager->isProcessingInputEvents())
{
throw std::logic_error("castRenderingRay can be used only in player scripts during processing of input events; "
"use asyncCastRenderingRay instead.");
}
MWPhysics::RayCastingResult res;
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false);
return res;
};
api["asyncCastRenderingRay"] =
[manager=context.mLuaManager](const LuaUtil::Callback& callback, const osg::Vec3f& from, const osg::Vec3f& to)
{
manager->addAction([manager, callback, from, to]
{
MWPhysics::RayCastingResult res;
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false);
manager->queueCallback(callback, sol::make_object(callback.mFunc.lua_state(), res));
});
};
api["activators"] = LObjectList{worldView->getActivatorsInScene()};
api["actors"] = LObjectList{worldView->getActorsInScene()};

View File

@ -9,12 +9,13 @@
namespace MWPhysics
{
struct RayCastingResult
class RayCastingResult
{
bool mHit;
osg::Vec3f mHitPos;
osg::Vec3f mHitNormal;
MWWorld::Ptr mHitObject;
public:
bool mHit;
osg::Vec3f mHitPos;
osg::Vec3f mHitNormal;
MWWorld::Ptr mHitObject;
};
class RayCastingInterface

View File

@ -2042,6 +2042,25 @@ namespace MWWorld
return facedObject;
}
bool World::castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
bool ignorePlayer, bool ignoreActors)
{
MWRender::RenderingManager::RayResult rayRes = mRendering->castRay(from, to, ignorePlayer, ignoreActors);
res.mHit = rayRes.mHit;
res.mHitPos = rayRes.mHitPointWorld;
res.mHitNormal = rayRes.mHitNormalWorld;
res.mHitObject = rayRes.mHitObject;
if (res.mHitObject.isEmpty() && rayRes.mHitRefnum.isSet())
{
for (CellStore* cellstore : mWorldScene->getActiveCells())
{
res.mHitObject = cellstore->searchViaRefNum(rayRes.mHitRefnum);
if (!res.mHitObject.isEmpty()) break;
}
}
return res.mHit;
}
bool World::isCellExterior() const
{
const CellStore *currentCell = mWorldScene->getCurrentCell();

View File

@ -421,6 +421,9 @@ namespace MWWorld
bool castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask, const MWWorld::ConstPtr& ignore) override;
bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
bool ignorePlayer, bool ignoreActors) override;
void setActorCollisionMode(const Ptr& ptr, bool internal, bool external) override;
bool isActorCollisionEnabled(const Ptr& ptr) override;

View File

@ -68,5 +68,22 @@
-- radius = 10,
-- })
---
-- 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.
-- In order to avoid threading issues can be used only in player scripts only in `onInputUpdate` or
-- in engine handlers for user input. In other cases use `asyncCastRenderingRay` instead.
-- @function [parent=#nearby] castRenderingRay
-- @param openmw.util#Vector3 from Start point of the ray.
-- @param openmw.util#Vector3 to End point of the ray.
-- @return #RayCastingResult
---
-- Asynchronously cast ray from one point to another and find the first visual intersection with anything in the scene.
-- @function [parent=#nearby] asyncCastRenderingRay
-- @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.
return nil