Control camera settings in-game

combined_windows_build
Petr Mikheev 3 years ago
parent f47e64b0f8
commit 860d5899c4

@ -66,6 +66,6 @@ $DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR openmw/*lua
cd $FILES_DIR/data
$DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR openmw_aux/*lua
$DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR scripts/omw/ai.lua
$DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR scripts/omw/camera.lua
$DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR scripts/omw/camera/camera.lua
$DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR scripts/omw/mwui/init.lua
$DOCUMENTOR_PATH -f doc -d $OUTPUT_DIR scripts/omw/settings/player.lua

@ -2,5 +2,5 @@ Interface Camera
================
.. raw:: html
:file: generated_html/scripts_omw_camera.html
:file: generated_html/scripts_omw_camera_camera.html

@ -12,6 +12,7 @@ set(BUILTIN_DATA_FILES
l10n/Calendar/en.yaml
l10n/Interface/en.yaml
l10n/OMWCamera/en.yaml
openmw_aux/util.lua
openmw_aux/time.lua
@ -21,9 +22,10 @@ set(BUILTIN_DATA_FILES
builtin.omwscripts
scripts/omw/ai.lua
scripts/omw/camera.lua
scripts/omw/head_bobbing.lua
scripts/omw/third_person.lua
scripts/omw/camera/camera.lua
scripts/omw/camera/head_bobbing.lua
scripts/omw/camera/third_person.lua
scripts/omw/camera/settings.lua
scripts/omw/console/player.lua
scripts/omw/console/global.lua
scripts/omw/console/local.lua

@ -1,8 +1,8 @@
PLAYER: scripts/omw/camera.lua
PLAYER: scripts/omw/mwui/init.lua
GLOBAL: scripts/omw/settings/global.lua
PLAYER: scripts/omw/settings/player.lua
PLAYER: scripts/omw/camera/camera.lua
NPC,CREATURE: scripts/omw/ai.lua
PLAYER: scripts/omw/console/player.lua
GLOBAL: scripts/omw/console/global.lua
CUSTOM: scripts/omw/console/local.lua
PLAYER: scripts/omw/mwui/init.lua
GLOBAL: scripts/omw/settings/global.lua
PLAYER: scripts/omw/settings/player.lua

@ -0,0 +1,59 @@
Camera: "Camera"
settingsPageDescription: "OpenMW camera settings"
thirdPersonSettings: "Third person mode"
viewOverShoulder: "View over the shoulder"
viewOverShoulderDescription: |
Controls third person view mode.
No: view is centered on the character's head. Crosshair is hidden.
Yes: in non-combat mode camera is positioned behind the character's shoulder, crosshair is always visible.
shoulderOffsetX: "Shoulder view horizontal offset"
shoulderOffsetXDescription: >
Horizontal offset of the camera in the view-over-the-shoulder mode.
For the left shoulder use a negative value.
shoulderOffsetY: "Shoulder view vertical offset"
shoulderOffsetYDescription: >
Vertical offset of the camera in the view-over-the-shoulder mode.
autoSwitchShoulder: "Auto switch shoulder"
autoSwitchShoulderDescription: >
When player is close to an obstacle, automatically switches camera
to the shoulder that is farther away from the obstacle.
zoomOutWhenMoveCoef: "Zoom out when move coef"
zoomOutWhenMoveCoefDescription: >
Slightly pulls camera away (or closer in case of a negative value) when the character moves.
Works only if "view over the shoulder" is enabled. To disable set it to zero (default: 20.0).
previewIfStandStill: "Preview if stand still"
previewIfStandStillDescription: >
If enabled then the character rotation is not synchonized with the camera rotation
while the character doesn't move and not in combat mode.
deferredPreviewRotation: "Deferred preview rotation"
deferredPreviewRotationDescription: |
If enabled then the character smoothly rotates to the view direction after exiting preview or vanity mode.
If disabled then the camera rotates rather than the character.
ignoreNC: "Ignore 'No Collision' flag"
ignoreNCDescription: >
Prevents camera from clipping through the objects with the NC (No Collision) NIF flag.
headBobbingSettings: "Head bobbing in first person view"
headBobbing_enabled: "Enabled"
headBobbing_enabledDescription: ""
headBobbing_step: "Base step length"
headBobbing_stepDescription: "The length of each step (default: 90.0)."
headBobbing_height: "Step height"
headBobbing_heightDescription: "The amplitude of the head bobbing (default: 3.0)."
headBobbing_roll: "Max roll angle"
headBobbing_rollDescription: "The maximum roll angle in degrees (default: 0.2)."

@ -1,20 +1,33 @@
local camera = require('openmw.camera')
local core = require('openmw.core')
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 async = require('openmw.async')
local Actor = require('openmw.types').Actor
local head_bobbing = require('scripts.omw.head_bobbing')
local third_person = require('scripts.omw.third_person')
local settings = require('scripts.omw.camera.settings').thirdPerson
local head_bobbing = require('scripts.omw.camera.head_bobbing')
local third_person = require('scripts.omw.camera.third_person')
local MODE = camera.MODE
local previewIfStandSill = settings._getBoolFromSettingsCfg('Camera', 'preview if stand still')
local showCrosshairInThirdPerson = settings._getBoolFromSettingsCfg('Camera', 'view over shoulder')
local previewIfStandStill = false
local showCrosshairInThirdPerson = false
local function updateSettings()
previewIfStandStill = settings:get('previewIfStandStill')
showCrosshairInThirdPerson = settings:get('viewOverShoulder')
camera.allowCharacterDeferredRotation(settings:get('deferredPreviewRotation'))
local collisionType = util.bitAnd(nearby.COLLISION_TYPE.Default, util.bitNot(nearby.COLLISION_TYPE.Actor))
collisionType = util.bitOr(collisionType, nearby.COLLISION_TYPE.Camera)
if settings:get('ignoreNC') then
collisionType = util.bitOr(collisionType, nearby.COLLISION_TYPE.VisualOnly)
end
camera.setCollisionType(collisionType)
end
local primaryMode
@ -24,17 +37,18 @@ local noHeadBobbing = 0
local noZoom = 0
local function init()
camera.setCollisionType(util.bitOr(util.bitAnd(nearby.COLLISION_TYPE.Default, util.bitNot(nearby.COLLISION_TYPE.Actor)), nearby.COLLISION_TYPE.Camera))
camera.setFieldOfView(camera.getBaseFieldOfView())
camera.allowCharacterDeferredRotation(settings._getBoolFromSettingsCfg('Camera', 'deferred preview rotation'))
if camera.getMode() == MODE.FirstPerson then
primaryMode = MODE.FirstPerson
else
primaryMode = MODE.ThirdPerson
camera.setMode(MODE.ThirdPerson)
end
updateSettings()
end
settings:subscribe(async:callback(updateSettings))
local smoothedSpeed = 0
local previewTimer = 0
@ -60,7 +74,7 @@ local function updatePOV(dt)
end
local idleTimer = 0
local vanityDelay = settings.getGMST('fVanityDelay')
local vanityDelay = core.getGMST('fVanityDelay')
local function updateVanity(dt)
if input.isIdle() then
@ -126,7 +140,7 @@ end
local function updateStandingPreview()
local mode = camera.getMode()
if not previewIfStandSill or noStandingPreview > 0
if not previewIfStandStill or noStandingPreview > 0
or mode == MODE.FirstPerson or mode == MODE.Static or mode == MODE.Vanity then
third_person.standingPreview = false
return
@ -204,7 +218,7 @@ return {
enableModeControl = function() noModeControl = math.max(0, noModeControl - 1) end,
--- @function [parent=#Camera] isStandingPreviewEnabled
isStandingPreviewEnabled = function() return previewIfStandSill and noStandingPreview == 0 end,
isStandingPreviewEnabled = function() return previewIfStandStill and noStandingPreview == 0 end,
--- @function [parent=#Camera] disableStandingPreview
disableStandingPreview = function() noStandingPreview = noStandingPreview + 1 end,
--- @function [parent=#Camera] enableStandingPreview

@ -1,21 +1,29 @@
local camera = require('openmw.camera')
local self = require('openmw.self')
local settings = require('openmw.settings')
local util = require('openmw.util')
local async = require('openmw.async')
local Actor = require('openmw.types').Actor
local doubleStepLength = settings._getFloatFromSettingsCfg('Camera', 'head bobbing step') * 2
local stepHeight = settings._getFloatFromSettingsCfg('Camera', 'head bobbing height')
local maxRoll = math.rad(settings._getFloatFromSettingsCfg('Camera', 'head bobbing roll'))
local M = {}
local settings = require('scripts.omw.camera.settings').headBobbing
local doubleStepLength, stepHeight, maxRoll
local function updateSettings()
M.enabled = settings:get('enabled')
doubleStepLength = settings:get('step') * 2
stepHeight = settings:get('height')
maxRoll = math.rad(settings:get('roll'))
end
updateSettings()
settings:subscribe(async:callback(updateSettings))
local effectWeight = 0
local totalMovement = 0
local M = {
enabled = settings._getBoolFromSettingsCfg('Camera', 'head bobbing')
}
-- Trajectory of each step is a scaled arc of 60 degrees.
local halfArc = math.rad(30)
local sampleArc = function(x) return 1 - math.cos(x * halfArc) end

@ -0,0 +1,95 @@
local storage = require('openmw.storage')
local async = require('openmw.async')
local I = require('openmw.interfaces')
I.Settings.registerPage({
key = 'OMWCamera',
l10n = 'OMWCamera',
name = 'Camera',
description = 'settingsPageDescription',
})
local thirdPersonGroup = 'SettingsOMWCameraThirdPerson'
local headBobbingGroup = 'SettingsOMWCameraHeadBobbing'
local function boolSetting(prefix, key, default)
return {
key = key,
renderer = 'checkbox',
name = prefix..key,
description = prefix..key..'Description',
default = default,
}
end
local function floatSetting(prefix, key, default)
return {
key = key,
renderer = 'number',
name = prefix..key,
description = prefix..key..'Description',
default = default,
}
end
I.Settings.registerGroup({
key = thirdPersonGroup,
page = 'OMWCamera',
l10n = 'OMWCamera',
name = 'thirdPersonSettings',
permanentStorage = true,
order = 0,
settings = {
boolSetting('', 'viewOverShoulder', true),
floatSetting('', 'shoulderOffsetX', 30),
floatSetting('', 'shoulderOffsetY', -10),
boolSetting('', 'autoSwitchShoulder', true),
floatSetting('', 'zoomOutWhenMoveCoef', 20),
boolSetting('', 'previewIfStandStill', true),
boolSetting('', 'deferredPreviewRotation', true),
boolSetting('', 'ignoreNC', true),
},
})
I.Settings.registerGroup({
key = headBobbingGroup,
page = 'OMWCamera',
l10n = 'OMWCamera',
name = 'headBobbingSettings',
permanentStorage = true,
order = 1,
settings = {
boolSetting('headBobbing_', 'enabled', true),
floatSetting('headBobbing_', 'step', 90),
floatSetting('headBobbing_', 'height', 3),
floatSetting('headBobbing_', 'roll', 0.2),
},
})
local settings = {
thirdPerson = storage.playerSection(thirdPersonGroup),
headBobbing = storage.playerSection(headBobbingGroup),
}
local function updateViewOverShoulderDisabled()
local disabled = not settings.thirdPerson:get('viewOverShoulder')
I.Settings.updateRendererArgument(thirdPersonGroup, 'shoulderOffsetX', {disabled = disabled})
I.Settings.updateRendererArgument(thirdPersonGroup, 'shoulderOffsetY', {disabled = disabled})
I.Settings.updateRendererArgument(thirdPersonGroup, 'autoSwitchShoulder', {disabled = disabled})
I.Settings.updateRendererArgument(thirdPersonGroup, 'zoomOutWhenMoveCoef', {disabled = disabled})
end
local function updateHeadBobbingDisabled()
local disabled = not settings.headBobbing:get('enabled')
I.Settings.updateRendererArgument(headBobbingGroup, 'step', {disabled = disabled, min = 1})
I.Settings.updateRendererArgument(headBobbingGroup, 'height', {disabled = disabled})
I.Settings.updateRendererArgument(headBobbingGroup, 'roll', {disabled = disabled, min = 0, max = 90})
end
updateViewOverShoulderDisabled()
updateHeadBobbingDisabled()
settings.thirdPerson:subscribe(async:callback(updateViewOverShoulderDisabled))
settings.headBobbing:subscribe(async:callback(updateHeadBobbingDisabled))
return settings

@ -1,31 +1,47 @@
local camera = require('openmw.camera')
local settings = require('openmw.settings')
local util = require('openmw.util')
local self = require('openmw.self')
local nearby = require('openmw.nearby')
local async = require('openmw.async')
local Actor = require('openmw.types').Actor
local settings = require('scripts.omw.camera.settings').thirdPerson
local MODE = camera.MODE
local STATE = { RightShoulder = 0, LeftShoulder = 1, Combat = 2, Swimming = 3 }
local M = {
baseDistance = settings._getFloatFromSettingsCfg('Camera', 'third person camera distance'),
baseDistance = 192,
preferredDistance = 0,
standingPreview = false,
noOffsetControl = 0,
}
local viewOverShoulder = settings._getBoolFromSettingsCfg('Camera', 'view over shoulder')
local autoSwitchShoulder = settings._getBoolFromSettingsCfg('Camera', 'auto switch shoulder')
local shoulderOffset = settings._getVector2FromSettingsCfg('Camera', 'view over shoulder offset')
local zoomOutWhenMoveCoef = settings._getFloatFromSettingsCfg('Camera', 'zoom out when move coef')
local viewOverShoulder, autoSwitchShoulder
local shoulderOffset
local zoomOutWhenMoveCoef
local defaultShoulder = (shoulderOffset.x > 0 and STATE.RightShoulder) or STATE.LeftShoulder
local rightShoulderOffset = util.vector2(math.abs(shoulderOffset.x), shoulderOffset.y)
local leftShoulderOffset = util.vector2(-math.abs(shoulderOffset.x), shoulderOffset.y)
local defaultShoulder, rightShoulderOffset, leftShoulderOffset
local combatOffset = util.vector2(0, 15)
local noThirdPersonLastFrame = true
local function updateSettings()
viewOverShoulder = settings:get('viewOverShoulder')
autoSwitchShoulder = settings:get('autoSwitchShoulder')
shoulderOffset = util.vector2(settings:get('shoulderOffsetX'),
settings:get('shoulderOffsetY'))
zoomOutWhenMoveCoef = settings:get('zoomOutWhenMoveCoef')
defaultShoulder = (shoulderOffset.x > 0 and STATE.RightShoulder) or STATE.LeftShoulder
rightShoulderOffset = util.vector2(math.abs(shoulderOffset.x), shoulderOffset.y)
leftShoulderOffset = util.vector2(-math.abs(shoulderOffset.x), shoulderOffset.y)
noThirdPersonLastFrame = true
end
updateSettings()
settings:subscribe(async:callback(updateSettings))
local state = defaultShoulder
local function ray(from, angle, limit)
@ -66,8 +82,6 @@ local function calculateDistance(smoothedSpeed)
+ smoothedSpeedSqr / (smoothedSpeedSqr + 300*300) * zoomOutWhenMoveCoef)
end
local noThirdPersonLastFrame = true
local function updateState()
local mode = camera.getMode()
local oldState = state
@ -80,9 +94,13 @@ local function updateState()
elseif not state then
state = defaultShoulder
end
if autoSwitchShoulder and (mode == MODE.ThirdPerson or state ~= oldState or noThirdPersonLastFrame)
if (mode == MODE.ThirdPerson or Actor.currentSpeed(self) > 0 or state ~= oldState or noThirdPersonLastFrame)
and (state == STATE.LeftShoulder or state == STATE.RightShoulder) then
trySwitchShoulder()
if autoSwitchShoulder then
trySwitchShoulder()
else
state = defaultShoulder
end
end
if oldState ~= state or noThirdPersonLastFrame then
-- State was changed, start focal point transition.
@ -116,7 +134,11 @@ function M.update(dt, smoothedSpeed)
if not viewOverShoulder then
M.preferredDistance = M.baseDistance
camera.setPreferredThirdPersonDistance(M.baseDistance)
noThirdPersonLastFrame = false
if noThirdPersonLastFrame then
camera.setFocalPreferredOffset(util.vector2(0, 0))
camera.instantTransition()
noThirdPersonLastFrame = false
end
return
end
Loading…
Cancel
Save