1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-19 19:10:12 +00:00

Update Lua bindings for the camera

This commit is contained in:
Petr Mikheev 2022-04-03 20:42:19 +02:00
parent 7186ea8ab4
commit 3af8ea5dfc
11 changed files with 104 additions and 7 deletions

View file

@ -64,6 +64,7 @@ namespace MWRender
{
class Animation;
class Camera;
class RenderingManager;
}
namespace MWMechanics
@ -664,6 +665,8 @@ namespace MWBase
virtual std::vector<MWWorld::Ptr> getAll(const std::string& id) = 0;
virtual Misc::Rng::Generator& getPrng() = 0;
virtual MWRender::RenderingManager* getRenderingManager() = 0;
};
}

View file

@ -1,6 +1,10 @@
#include "luabindings.hpp"
#include <components/lua/utilpackage.hpp>
#include <components/settings/settings.hpp>
#include "../mwrender/camera.hpp"
#include "../mwrender/renderingmanager.hpp"
namespace MWLua
{
@ -10,6 +14,7 @@ namespace MWLua
sol::table initCameraPackage(const Context& context)
{
MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera();
MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager();
sol::table api(context.mLua->sol(), sol::create);
api["MODE"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with(
@ -77,6 +82,31 @@ namespace MWLua
api["setFocalTransitionSpeed"] = [camera](float v) { camera->setFocalPointTransitionSpeed(v); };
api["instantTransition"] = [camera]() { camera->instantTransition(); };
api["getCollisionType"] = [camera]() { return camera->getCollisionType(); };
api["setCollisionType"] = [camera](int collisionType) { camera->setCollisionType(collisionType); };
api["getBaseFieldOfView"] = []()
{
return osg::DegreesToRadians(std::clamp(Settings::Manager::getFloat("field of view", "Camera"), 1.f, 179.f));
};
api["getFieldOfView"] = [renderingManager]() { return osg::DegreesToRadians(renderingManager->getFieldOfView()); };
api["setFieldOfView"] = [renderingManager](float v) { renderingManager->setFieldOfView(osg::RadiansToDegrees(v)); };
api["getViewTransform"] = [camera]() { return LuaUtil::TransformM{camera->getViewMatrix()}; };
api["viewportToWorldVector"] = [camera, renderingManager](osg::Vec2f pos) -> osg::Vec3f
{
double width = Settings::Manager::getInt("resolution x", "Video");
double height = Settings::Manager::getInt("resolution y", "Video");
double aspect = (height == 0.0) ? 1.0 : width / height;
double fovTan = std::tan(osg::DegreesToRadians(renderingManager->getFieldOfView()) / 2);
osg::Matrixf invertedViewMatrix;
invertedViewMatrix.invert(camera->getViewMatrix());
float x = (pos.x() * 2 - 1) * aspect * fovTan;
float y = (1 - pos.y() * 2) * fovTan;
return invertedViewMatrix.preMult(osg::Vec3f(x, y, -1)) - camera->getPosition();
};
return LuaUtil::makeReadOnly(api);
}

View file

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

View file

@ -53,6 +53,7 @@ namespace MWRender
Camera::Camera (osg::Camera* camera)
: mHeightScale(1.f),
mCollisionType(MWPhysics::CollisionType::CollisionType_Default & ~MWPhysics::CollisionType::CollisionType_Actor),
mCamera(camera),
mAnimation(nullptr),
mFirstPersonView(true),
@ -127,6 +128,7 @@ namespace MWRender
pos = calculateFirstPersonPosition(recalculatedTrackedPosition);
}
cam->setViewMatrixAsLookAt(pos, pos + forward, up);
mViewMatrix = cam->getViewMatrix();
}
void Camera::update(float duration, bool paused)
@ -174,7 +176,6 @@ namespace MWRender
constexpr float focalObstacleLimit = 10.f;
const auto* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting();
constexpr int collisionType = (MWPhysics::CollisionType::CollisionType_Default & ~MWPhysics::CollisionType::CollisionType_Actor);
// Adjust focal point to prevent clipping.
osg::Vec3d focalOffset = getFocalPointOffset();
@ -184,7 +185,7 @@ namespace MWRender
float offsetLen = focalOffset.length();
if (offsetLen > 0)
{
MWPhysics::RayCastingResult result = rayCasting->castSphere(focal - focalOffset, focal, focalObstacleLimit, collisionType);
MWPhysics::RayCastingResult result = rayCasting->castSphere(focal - focalOffset, focal, focalObstacleLimit, mCollisionType);
if (result.mHit)
{
double adjustmentCoef = -(result.mHitPos + result.mHitNormal * focalObstacleLimit - focal).length() / offsetLen;
@ -196,7 +197,7 @@ namespace MWRender
mCameraDistance = mPreferredCameraDistance;
osg::Quat orient = osg::Quat(mPitch + mExtraPitch, osg::Vec3d(1,0,0)) * osg::Quat(mYaw + mExtraYaw, osg::Vec3d(0,0,1));
osg::Vec3d offset = orient * osg::Vec3d(0.f, -mCameraDistance, 0.f);
MWPhysics::RayCastingResult result = rayCasting->castSphere(focal, focal + offset, cameraObstacleLimit, collisionType);
MWPhysics::RayCastingResult result = rayCasting->castSphere(focal, focal + offset, cameraObstacleLimit, mCollisionType);
if (result.mHit)
{
mCameraDistance = (result.mHitPos + result.mHitNormal * cameraObstacleLimit - focal).length();
@ -211,7 +212,7 @@ namespace MWRender
if (mMode == newMode)
return;
Mode oldMode = mMode;
if (!force && (newMode == Mode::FirstPerson || oldMode == Mode::FirstPerson) && !mAnimation->upperBodyReady())
if (!force && (newMode == Mode::FirstPerson || oldMode == Mode::FirstPerson) && mAnimation && !mAnimation->upperBodyReady())
{
// Changing the view will stop all playing animations, so if we are playing
// anything important, queue the view change for later

View file

@ -5,6 +5,7 @@
#include <string>
#include <osg/ref_ptr>
#include <osg/Matrix>
#include <osg/Vec3>
#include <osg/Vec3d>
@ -95,11 +96,17 @@ namespace MWRender
void setFirstPersonOffset(const osg::Vec3f& v) { mFirstPersonOffset = v; }
osg::Vec3f getFirstPersonOffset() const { return mFirstPersonOffset; }
int getCollisionType() const { return mCollisionType; }
void setCollisionType(int collisionType) { mCollisionType = collisionType; }
const osg::Matrixf& getViewMatrix() const { return mViewMatrix; }
private:
MWWorld::Ptr mTrackingPtr;
osg::ref_ptr<const osg::Node> mTrackingNode;
osg::Vec3d mTrackedPosition;
float mHeightScale;
int mCollisionType;
osg::ref_ptr<osg::Camera> mCamera;
@ -121,6 +128,7 @@ namespace MWRender
float mExtraPitch = 0, mExtraYaw = 0;
bool mLockPitch = false, mLockYaw = false;
osg::Vec3d mPosition;
osg::Matrixf mViewMatrix;
float mCameraDistance, mPreferredCameraDistance;

View file

@ -817,6 +817,11 @@ namespace MWRender
updateNavMesh();
updateRecastMesh();
if (mUpdateProjectionMatrix)
{
mUpdateProjectionMatrix = false;
updateProjectionMatrix();
}
mCamera->update(dt, paused);
bool isUnderwater = mWater->isUnderwater(mCamera->getPosition());
@ -1161,8 +1166,7 @@ namespace MWRender
// Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may disappear.
// Limit FOV here just for sure, otherwise viewing distance can be too high.
fov = std::min(mFieldOfView, 140.f);
float distanceMult = std::cos(osg::DegreesToRadians(fov)/2.f);
float distanceMult = std::cos(osg::DegreesToRadians(std::min(fov, 140.f))/2.f);
mTerrain->setViewDistance(mViewDistance * (distanceMult ? 1.f/distanceMult : 1.f));
}
@ -1300,6 +1304,17 @@ namespace MWRender
}
}
void RenderingManager::setFieldOfView(float val)
{
mFieldOfView = val;
mUpdateProjectionMatrix = true;
}
float RenderingManager::getFieldOfView() const
{
return mFieldOfViewOverridden ? mFieldOfViewOverridden : mFieldOfView;
}
osg::Vec3f RenderingManager::getHalfExtents(const MWWorld::ConstPtr& object) const
{
osg::Vec3f halfExtents(0, 0, 0);

View file

@ -214,6 +214,8 @@ namespace MWRender
/// temporarily override the field of view with given value.
void overrideFieldOfView(float val);
void setFieldOfView(float val);
float getFieldOfView() const;
/// reset a previous overrideFieldOfView() call, i.e. revert to field of view specified in the settings file.
void resetFieldOfView();
@ -301,6 +303,7 @@ namespace MWRender
float mFieldOfViewOverride;
float mFieldOfView;
float mFirstPersonFieldOfView;
bool mUpdateProjectionMatrix = false;
void operator = (const RenderingManager&);
RenderingManager(const RenderingManager&);

View file

@ -743,6 +743,8 @@ namespace MWWorld
std::vector<MWWorld::Ptr> getAll(const std::string& id) override;
Misc::Rng::Generator& getPrng() override;
MWRender::RenderingManager* getRenderingManager() override { return mRendering.get(); }
};
}

View file

@ -4,6 +4,7 @@ local input = require('openmw.input')
local settings = require('openmw.settings')
local util = require('openmw.util')
local self = require('openmw.self')
local nearby = require('openmw.nearby')
local Actor = require('openmw.types').Actor
@ -23,6 +24,8 @@ local noHeadBobbing = 0
local noZoom = 0
local function init()
camera.setCollisionType(util.bitAnd(nearby.COLLISION_TYPE.Default, util.bitNot(nearby.COLLISION_TYPE.Actor)))
camera.setFieldOfView(camera.getBaseFieldOfView())
camera.allowCharacterDeferredRotation(settings._getBoolFromSettingsCfg('Camera', 'deferred preview rotation'))
if camera.getMode() == MODE.FirstPerson then
primaryMode = MODE.FirstPerson

View file

@ -78,6 +78,8 @@ local function updateState()
state = STATE.Swimming
elseif oldState == STATE.Combat or oldState == STATE.Swimming then
state = defaultShoulder
elseif not state then
state = defaultShoulder
end
if autoSwitchShoulder and (mode == MODE.ThirdPerson or state ~= oldState or noThirdPersonLastFrame)
and (state == STATE.LeftShoulder or state == STATE.RightShoulder) then

View file

@ -166,6 +166,36 @@
-- Make instant the current transition of camera focal point and the current deferred rotation (see `allowCharacterDeferredRotation`).
-- @function [parent=#camera] instantTransition
--- Get current camera collision type (see @{openmw.nearby#COLLISION_TYPE}).
-- @function [parent=#camera] getCollisionType
-- @return #number
--- Set camera collision type (see @{openmw.nearby#COLLISION_TYPE}).
-- @function [parent=#camera] setCollisionType
-- @param #number collisionType
--- Return base field of view vertical angle in radians
-- @function [parent=#camera] getBaseFieldOfView
-- @return #number
--- Return current field of view vertical angle in radians
-- @function [parent=#camera] getFieldOfView
-- @return #number
--- Set field of view
-- @function [parent=#camera] setFieldOfView
-- @param #number fov Field of view vertical angle in radians
--- Get world to local transform for the camera.
-- @function [parent=#camera] getViewTransform
-- @return openmw.util#Transform
--- Get vector from the camera to the world for the given point in viewport.
-- (0, 0) is the top left corner of the screen.
-- @function [parent=#camera] viewportToWorldVector
-- @param openmw.util#Vector2 normalizedScreenPos
-- @return openmw.util#Vector3
return nil