@quenty/camera 4.4.0 → 5.0.1-canary.238.2c4d310.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +2 -2
- package/package.json +14 -14
- package/src/Client/CameraStackService.lua +85 -27
- package/src/Client/CameraState.lua +23 -55
- package/src/Client/CameraUtils.lua +52 -4
- package/src/Client/CameraUtils.story.lua +3 -3
- package/src/Client/Controls/CameraControls.lua +7 -5
- package/src/Client/Controls/CameraGamepadInputUtils.lua +3 -3
- package/src/Client/Controls/GamepadRotateModel.lua +4 -2
- package/src/Client/Effects/CameraEffectUtils.lua +19 -0
- package/src/Client/Effects/CustomCameraEffect.lua +15 -4
- package/src/Client/Effects/DefaultCamera.lua +32 -3
- package/src/Client/Effects/FadeBetween/FadeBetweenCamera.lua +15 -2
- package/src/Client/Effects/FadeBetween/FadeBetweenCamera2.lua +14 -3
- package/src/Client/Effects/FadeBetween/FadeBetweenCamera3.lua +15 -2
- package/src/Client/Effects/FadeBetween/FadeBetweenCamera4.lua +14 -3
- package/src/Client/Effects/FadingCamera.lua +13 -2
- package/src/Client/Effects/HeartbeatCamera.lua +13 -4
- package/src/Client/Effects/ImpulseCamera.lua +16 -3
- package/src/Client/Effects/InverseFader.lua +4 -2
- package/src/Client/Effects/LagPointCamera.lua +5 -3
- package/src/Client/Effects/PointCamera.lua +10 -6
- package/src/Client/Effects/PushCamera.lua +24 -5
- package/src/Client/Effects/RotatedCamera.lua +17 -5
- package/src/Client/Effects/SmoothPositionCamera.lua +4 -2
- package/src/Client/Effects/SmoothRotatedCamera.lua +7 -5
- package/src/Client/Effects/SmoothZoomedCamera.lua +7 -4
- package/src/Client/Effects/SummedCamera.lua +18 -10
- package/src/Client/Effects/TrackCamera.lua +27 -6
- package/src/Client/Effects/XZPlaneLockCamera.lua +4 -2
- package/src/Client/Effects/ZoomedCamera.lua +16 -10
- package/src/Client/Input/CameraInputUtils.lua +3 -3
- package/src/Client/Input/CameraTouchInputUtils.lua +13 -5
- package/src/Client/Utility/CameraFrame.lua +82 -4
- package/src/Client/Utility/CameraFrame.story.lua +3 -3
- package/src/Client/Utility/CameraStateTweener.lua +69 -8
- package/src/Client/Utility/FieldOfViewUtils.lua +34 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [5.0.1-canary.238.2c4d310.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@5.0.0...@quenty/camera@5.0.1-canary.238.2c4d310.0) (2021-12-29)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @quenty/camera
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [5.0.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@4.4.0...@quenty/camera@5.0.0) (2021-12-22)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @quenty/camera
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
# [4.4.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@4.3.1...@quenty/camera@4.4.0) (2021-12-18)
|
|
7
23
|
|
|
8
24
|
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
## Camera
|
|
2
2
|
<div align="center">
|
|
3
|
-
<a href="http://quenty.github.io/
|
|
3
|
+
<a href="http://quenty.github.io/NevermoreEngine/">
|
|
4
4
|
<img src="https://img.shields.io/badge/docs-website-green.svg" alt="Documentation" />
|
|
5
5
|
</a>
|
|
6
6
|
<a href="https://discord.gg/mhtGUS8">
|
|
7
|
-
<img src="https://img.shields.io/
|
|
7
|
+
<img src="https://img.shields.io/discord/385151591524597761?color=5865F2&label=discord&logo=discord&logoColor=white" alt="Discord" />
|
|
8
8
|
</a>
|
|
9
9
|
<a href="https://github.com/Quenty/NevermoreEngine/actions">
|
|
10
10
|
<img src="https://github.com/Quenty/NevermoreEngine/actions/workflows/build.yml/badge.svg" alt="Build and release status" />
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/camera",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.1-canary.238.2c4d310.0",
|
|
4
4
|
"description": "Quenty's camera system for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,23 +25,23 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/acceltween": "
|
|
29
|
-
"@quenty/baseobject": "
|
|
30
|
-
"@quenty/cframeutils": "
|
|
31
|
-
"@quenty/cubicspline": "
|
|
32
|
-
"@quenty/inputobjectutils": "
|
|
33
|
-
"@quenty/loader": "
|
|
34
|
-
"@quenty/maid": "
|
|
35
|
-
"@quenty/math": "
|
|
36
|
-
"@quenty/qframe": "
|
|
37
|
-
"@quenty/servicebag": "
|
|
38
|
-
"@quenty/spring": "
|
|
28
|
+
"@quenty/acceltween": "2.0.1-canary.238.2c4d310.0",
|
|
29
|
+
"@quenty/baseobject": "3.2.1-canary.238.2c4d310.0",
|
|
30
|
+
"@quenty/cframeutils": "2.0.1-canary.238.2c4d310.0",
|
|
31
|
+
"@quenty/cubicspline": "3.2.1-canary.238.2c4d310.0",
|
|
32
|
+
"@quenty/inputobjectutils": "2.0.2-canary.238.2c4d310.0",
|
|
33
|
+
"@quenty/loader": "3.1.2-canary.238.2c4d310.0",
|
|
34
|
+
"@quenty/maid": "2.0.2-canary.238.2c4d310.0",
|
|
35
|
+
"@quenty/math": "2.0.1-canary.238.2c4d310.0",
|
|
36
|
+
"@quenty/qframe": "3.3.1-canary.238.2c4d310.0",
|
|
37
|
+
"@quenty/servicebag": "3.2.2-canary.238.2c4d310.0",
|
|
38
|
+
"@quenty/spring": "3.0.1-canary.238.2c4d310.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@quenty/camerastoryutils": "
|
|
41
|
+
"@quenty/camerastoryutils": "3.3.1-canary.238.2c4d310.0"
|
|
42
42
|
},
|
|
43
43
|
"publishConfig": {
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "2c4d310b84afd0570d89667dc5d4aa69a0ef304a"
|
|
47
47
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
--[=[
|
|
2
|
+
Holds camera states and allows for the last camera state to be retrieved. Also
|
|
3
|
+
initializes an impulse and default camera as the bottom of the stack. Is a singleton.
|
|
4
|
+
|
|
5
|
+
@class CameraStackService
|
|
6
|
+
]=]
|
|
4
7
|
|
|
5
8
|
local require = require(script.Parent.loader).load(script)
|
|
6
9
|
|
|
@@ -17,6 +20,10 @@ assert(RunService:IsClient(), "[CameraStackService] - Only require CameraStackSe
|
|
|
17
20
|
|
|
18
21
|
local CameraStackService = {}
|
|
19
22
|
|
|
23
|
+
--[=[
|
|
24
|
+
Initializes a new camera stack. Should be done via the ServiceBag.
|
|
25
|
+
@param serviceBag ServiceBag
|
|
26
|
+
]=]
|
|
20
27
|
function CameraStackService:Init(serviceBag)
|
|
21
28
|
assert(ServiceBag.isServiceBag(serviceBag), "Not a valid service bag")
|
|
22
29
|
|
|
@@ -58,12 +65,20 @@ function CameraStackService:Init(serviceBag)
|
|
|
58
65
|
end)
|
|
59
66
|
end
|
|
60
67
|
|
|
68
|
+
--[=[
|
|
69
|
+
Prevents the default camera from being used
|
|
70
|
+
@param doNotUseDefaultCamera boolean
|
|
71
|
+
]=]
|
|
61
72
|
function CameraStackService:SetDoNotUseDefaultCamera(doNotUseDefaultCamera)
|
|
62
73
|
assert(not self._stack, "Already initialized")
|
|
63
74
|
|
|
64
75
|
self._doNotUseDefaultCamera = doNotUseDefaultCamera
|
|
65
76
|
end
|
|
66
77
|
|
|
78
|
+
--[=[
|
|
79
|
+
Pushes a disable state onto the camera stack
|
|
80
|
+
@return function -- Function to cancel disable
|
|
81
|
+
]=]
|
|
67
82
|
function CameraStackService:PushDisable()
|
|
68
83
|
assert(self._stack, "Not initialized")
|
|
69
84
|
|
|
@@ -76,8 +91,9 @@ function CameraStackService:PushDisable()
|
|
|
76
91
|
end
|
|
77
92
|
end
|
|
78
93
|
|
|
79
|
-
|
|
80
|
-
|
|
94
|
+
--[=[
|
|
95
|
+
Outputs the camera stack. Intended for diagnostics.
|
|
96
|
+
]=]
|
|
81
97
|
function CameraStackService:PrintCameraStack()
|
|
82
98
|
assert(self._stack, "Stack is not initialized yet")
|
|
83
99
|
|
|
@@ -86,39 +102,65 @@ function CameraStackService:PrintCameraStack()
|
|
|
86
102
|
end
|
|
87
103
|
end
|
|
88
104
|
|
|
89
|
-
|
|
90
|
-
|
|
105
|
+
--[=[
|
|
106
|
+
Returns the default camera
|
|
107
|
+
@return SummedCamera -- DefaultCamera + ImpulseCamera
|
|
108
|
+
]=]
|
|
91
109
|
function CameraStackService:GetDefaultCamera()
|
|
92
110
|
assert(self._defaultCamera, "Not initialized")
|
|
93
111
|
|
|
94
112
|
return self._defaultCamera
|
|
95
113
|
end
|
|
96
114
|
|
|
97
|
-
|
|
98
|
-
|
|
115
|
+
--[=[
|
|
116
|
+
Returns the impulse camera. Useful for adding camera shake.
|
|
117
|
+
|
|
118
|
+
Shaking the camera:
|
|
119
|
+
```lua
|
|
120
|
+
self._cameraStackService:GetImpulseCamera():Impulse(Vector3.new(0.25, 0, 0.25*(math.random()-0.5)))
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
You can also sum the impulse camera into another effect to layer the shake on top of the effect
|
|
124
|
+
as desired.
|
|
125
|
+
|
|
126
|
+
```lua
|
|
127
|
+
-- Adding global custom camera shake to a custom camera effect
|
|
128
|
+
local customCameraEffect = ...
|
|
129
|
+
return (customCameraEffect + self._cameraStackService:GetImpulseCamera()):SetMode("Relative")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
@return ImpulseCamera
|
|
133
|
+
]=]
|
|
99
134
|
function CameraStackService:GetImpulseCamera()
|
|
100
135
|
assert(self._impulseCamera, "Not initialized")
|
|
101
136
|
|
|
102
137
|
return self._impulseCamera
|
|
103
138
|
end
|
|
104
139
|
|
|
105
|
-
|
|
106
|
-
|
|
140
|
+
--[=[
|
|
141
|
+
Returns the default camera without any impulse cameras
|
|
142
|
+
@return DefaultCamera
|
|
143
|
+
]=]
|
|
107
144
|
function CameraStackService:GetRawDefaultCamera()
|
|
108
145
|
assert(self._rawDefaultCamera, "Not initialized")
|
|
109
146
|
|
|
110
147
|
return self._rawDefaultCamera
|
|
111
148
|
end
|
|
112
149
|
|
|
150
|
+
--[=[
|
|
151
|
+
Gets the camera current on the top of the stack
|
|
152
|
+
@return CameraEffect
|
|
153
|
+
]=]
|
|
113
154
|
function CameraStackService:GetTopCamera()
|
|
114
155
|
assert(self._stack, "Not initialized")
|
|
115
156
|
|
|
116
157
|
return self._stack[#self._stack]
|
|
117
158
|
end
|
|
118
159
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
160
|
+
--[=[
|
|
161
|
+
Retrieves the top state off the stack at this time
|
|
162
|
+
@return CameraState?
|
|
163
|
+
]=]
|
|
122
164
|
function CameraStackService:GetTopState()
|
|
123
165
|
assert(self._stack, "Stack is not initialized yet")
|
|
124
166
|
|
|
@@ -139,9 +181,12 @@ function CameraStackService:GetTopState()
|
|
|
139
181
|
end
|
|
140
182
|
end
|
|
141
183
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
184
|
+
--[=[
|
|
185
|
+
Returns a new camera state that retrieves the state below its set state.
|
|
186
|
+
|
|
187
|
+
@return CustomCameraEffect -- Effect below
|
|
188
|
+
@return (CameraState) -> () -- Function to set the state
|
|
189
|
+
]=]
|
|
145
190
|
function CameraStackService:GetNewStateBelow()
|
|
146
191
|
assert(self._stack, "Stack is not initialized yet")
|
|
147
192
|
|
|
@@ -166,10 +211,12 @@ function CameraStackService:GetNewStateBelow()
|
|
|
166
211
|
end
|
|
167
212
|
end
|
|
168
213
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
214
|
+
--[=[
|
|
215
|
+
Retrieves the index of a state
|
|
216
|
+
@param state CameraEffect
|
|
217
|
+
@return number? -- index
|
|
218
|
+
|
|
219
|
+
]=]
|
|
173
220
|
function CameraStackService:GetIndex(state)
|
|
174
221
|
assert(self._stack, "Stack is not initialized yet")
|
|
175
222
|
|
|
@@ -180,15 +227,25 @@ function CameraStackService:GetIndex(state)
|
|
|
180
227
|
end
|
|
181
228
|
end
|
|
182
229
|
|
|
230
|
+
--[=[
|
|
231
|
+
Returns the current stack.
|
|
232
|
+
|
|
233
|
+
:::warning
|
|
234
|
+
Do not modify this stack, this is the raw memory of the stack
|
|
235
|
+
:::
|
|
236
|
+
|
|
237
|
+
@return { CameraState<T> }
|
|
238
|
+
]=]
|
|
183
239
|
function CameraStackService:GetStack()
|
|
184
240
|
assert(self._stack, "Not initialized")
|
|
185
241
|
|
|
186
242
|
return self._stack
|
|
187
243
|
end
|
|
188
244
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
245
|
+
--[=[
|
|
246
|
+
Removes the state from the stack
|
|
247
|
+
@param state CameraState
|
|
248
|
+
]=]
|
|
192
249
|
function CameraStackService:Remove(state)
|
|
193
250
|
assert(self._stack, "Stack is not initialized yet")
|
|
194
251
|
|
|
@@ -199,9 +256,10 @@ function CameraStackService:Remove(state)
|
|
|
199
256
|
end
|
|
200
257
|
end
|
|
201
258
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
259
|
+
--[=[
|
|
260
|
+
Adds the state from the stack
|
|
261
|
+
@param state CameraState
|
|
262
|
+
]=]
|
|
205
263
|
function CameraStackService:Add(state)
|
|
206
264
|
assert(self._stack, "Stack is not initialized yet")
|
|
207
265
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
--[=[
|
|
2
|
+
Data container for the state of a camera.
|
|
3
|
+
@class CameraState
|
|
4
|
+
]=]
|
|
3
5
|
|
|
4
6
|
local require = require(script.Parent.loader).load(script)
|
|
5
7
|
|
|
@@ -9,14 +11,21 @@ local CameraFrame = require("CameraFrame")
|
|
|
9
11
|
local CameraState = {}
|
|
10
12
|
CameraState.ClassName = "CameraState"
|
|
11
13
|
|
|
14
|
+
--[=[
|
|
15
|
+
Returns true if the result is a camera state
|
|
16
|
+
@param value any
|
|
17
|
+
@return boolean
|
|
18
|
+
]=]
|
|
12
19
|
function CameraState.isCameraState(value)
|
|
13
20
|
return getmetatable(value) == CameraState
|
|
14
21
|
end
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
--[=[
|
|
24
|
+
Constructs a new CameraState
|
|
25
|
+
@param cameraFrame CameraFrame | Camera
|
|
26
|
+
@param cameraFrameDerivative CameraFrame?
|
|
27
|
+
@return CameraState
|
|
28
|
+
]=]
|
|
20
29
|
function CameraState.new(cameraFrame, cameraFrameDerivative)
|
|
21
30
|
local self = setmetatable({}, CameraState)
|
|
22
31
|
|
|
@@ -36,6 +45,10 @@ function CameraState.new(cameraFrame, cameraFrameDerivative)
|
|
|
36
45
|
return self
|
|
37
46
|
end
|
|
38
47
|
|
|
48
|
+
--[=[
|
|
49
|
+
@prop cframe CFrame
|
|
50
|
+
@within CameraState
|
|
51
|
+
]=]
|
|
39
52
|
function CameraState:__index(index)
|
|
40
53
|
if index == "CFrame" then
|
|
41
54
|
return self.CameraFrame.CFrame
|
|
@@ -66,55 +79,10 @@ function CameraState:__newindex(index, value)
|
|
|
66
79
|
end
|
|
67
80
|
end
|
|
68
81
|
|
|
69
|
-
--
|
|
70
|
-
|
|
71
|
-
--
|
|
72
|
-
|
|
73
|
-
-- return CameraState.new(a.QFrame + b.QFrame, a.FieldOfView + b.FieldOfView)
|
|
74
|
-
-- end
|
|
75
|
-
|
|
76
|
-
-- function CameraState.__sub(a, b)
|
|
77
|
-
-- assert(CameraState.isCameraState(a) and CameraState.isCameraState(b),
|
|
78
|
-
-- "CameraState - non-CameraState attempted")
|
|
79
|
-
|
|
80
|
-
-- return CameraState.new(a.QFrame - b.QFrame, a.FieldOfView - b.FieldOfView)
|
|
81
|
-
-- end
|
|
82
|
-
|
|
83
|
-
-- function CameraState.__unm(a)
|
|
84
|
-
-- return CameraState.new(-a.QFrame, -a.FieldOfView)
|
|
85
|
-
-- end
|
|
86
|
-
|
|
87
|
-
-- function CameraState.__mul(a, b)
|
|
88
|
-
-- if type(a) == "number" and CameraState.isCameraState(b) then
|
|
89
|
-
-- return CameraState.new(a*b.QFrame, a*b.FieldOfView)
|
|
90
|
-
-- elseif CameraState.isCameraState(b) and type(b) == "number" then
|
|
91
|
-
-- return CameraState.new(a.QFrame*b, a.FieldOfView*b)
|
|
92
|
-
-- elseif CameraState.isCameraState(a) and CameraState.isCameraState(b) then
|
|
93
|
-
-- return CameraState.new(a.QFrame*b.QFrame, a.FieldOfView*b.FieldOfView)
|
|
94
|
-
-- else
|
|
95
|
-
-- error("CameraState * non-CameraState attempted")
|
|
96
|
-
-- end
|
|
97
|
-
-- end
|
|
98
|
-
|
|
99
|
-
-- function CameraState.__div(a, b)
|
|
100
|
-
-- if CameraState.isCameraState(a) and type(b) == "number" then
|
|
101
|
-
-- return CameraState.new(a.QFrame/b, a.FieldOfView/b)
|
|
102
|
-
-- else
|
|
103
|
-
-- error("CameraState * non-CameraState attempted")
|
|
104
|
-
-- end
|
|
105
|
-
-- end
|
|
106
|
-
|
|
107
|
-
-- function CameraState.__pow(a, b)
|
|
108
|
-
-- if CameraState.isCameraState(a) and type(b) == "number" then
|
|
109
|
-
-- return CameraState.new(a.QFrame^b, a.FieldOfView^b)
|
|
110
|
-
-- else
|
|
111
|
-
-- error("CameraState ^ non-CameraState attempted")
|
|
112
|
-
-- end
|
|
113
|
-
-- end
|
|
114
|
-
|
|
115
|
-
--- Set another camera state. Typically used to set Workspace.CurrentCamera's state to match this camera's state
|
|
116
|
-
-- @tparam Camera camera A CameraState to set, also accepts a Roblox Camera
|
|
117
|
-
-- @treturn nil
|
|
82
|
+
--[=[
|
|
83
|
+
Set another camera state. Typically used to set Workspace.CurrentCamera's state to match this camera's state
|
|
84
|
+
@param camera Camera -- A CameraState to set, also accepts a Roblox Camera
|
|
85
|
+
]=]
|
|
118
86
|
function CameraState:Set(camera)
|
|
119
87
|
camera.FieldOfView = self.FieldOfView
|
|
120
88
|
camera.CFrame = self.CFrame
|
|
@@ -1,19 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
--[=[
|
|
2
|
+
Utility methods for cameras. These are great for viewport frames.
|
|
3
|
+
|
|
4
|
+
```lua
|
|
5
|
+
-- Sample viewport frame fitting of a model
|
|
6
|
+
local viewportFrame = ...
|
|
7
|
+
local camera = viewportFrame.CurrentCamera
|
|
8
|
+
local model = viewportFrame:FindFirstChildWhichIsA("Model")
|
|
9
|
+
|
|
10
|
+
RunService.RenderStepped:Connect(function()
|
|
11
|
+
local cframe, size = model:GetBoundingBox()
|
|
12
|
+
local size = viewportFrame.AbsoluteSize
|
|
13
|
+
local aspectRatio = size.x/size.y
|
|
14
|
+
local dist = CameraUtils.fitBoundingBoxToCamera(size, camera.FieldOfView, aspectRatio)
|
|
15
|
+
camera.CFrame = cframe.p + CFrame.Angles(0, math.pi*os.clock() % math.pi, -math.pi/8)
|
|
16
|
+
:vectorToWorldSpace(Vector3.new(0, 0, -dist))
|
|
17
|
+
end)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
@class CameraUtils
|
|
21
|
+
]=]
|
|
3
22
|
|
|
4
23
|
local CameraUtils = {}
|
|
5
24
|
|
|
25
|
+
--[=[
|
|
26
|
+
Computes the diameter of a cubeid
|
|
27
|
+
|
|
28
|
+
@param size Vector3
|
|
29
|
+
@return number
|
|
30
|
+
]=]
|
|
6
31
|
function CameraUtils.getCubeoidDiameter(size)
|
|
7
32
|
return math.sqrt(size.x^2 + size.y^2 + size.z^2)
|
|
8
33
|
end
|
|
9
34
|
|
|
10
|
-
|
|
11
|
-
|
|
35
|
+
--[=[
|
|
36
|
+
Use spherical bounding box to calculate how far back to move a camera
|
|
37
|
+
See: https://community.khronos.org/t/zoom-to-fit-screen/59857/12
|
|
38
|
+
|
|
39
|
+
@param size Vector3 -- Size of the bounding box
|
|
40
|
+
@param fovDeg number -- Field of view in degrees (vertical)
|
|
41
|
+
@param aspectRatio number -- Aspect ratio of the screen
|
|
42
|
+
@return number -- Distance to move the camera back from the bounding box
|
|
43
|
+
]=]
|
|
12
44
|
function CameraUtils.fitBoundingBoxToCamera(size, fovDeg, aspectRatio)
|
|
13
45
|
local radius = CameraUtils.getCubeoidDiameter(size)/2
|
|
14
46
|
return CameraUtils.fitSphereToCamera(radius, fovDeg, aspectRatio)
|
|
15
47
|
end
|
|
16
48
|
|
|
49
|
+
--[=[
|
|
50
|
+
Fits a sphere to the camera, computing how far back to zoom the camera from
|
|
51
|
+
the center of the sphere.
|
|
52
|
+
|
|
53
|
+
@param radius number -- Radius of the sphere
|
|
54
|
+
@param fovDeg number -- Field of view in degrees (vertical)
|
|
55
|
+
@param aspectRatio number -- Aspect ratio of the screen
|
|
56
|
+
@return number -- Distance to move the camera back from the bounding box
|
|
57
|
+
]=]
|
|
17
58
|
function CameraUtils.fitSphereToCamera(radius, fovDeg, aspectRatio)
|
|
18
59
|
local halfFov = 0.5 * math.rad(fovDeg)
|
|
19
60
|
if aspectRatio < 1 then
|
|
@@ -23,6 +64,13 @@ function CameraUtils.fitSphereToCamera(radius, fovDeg, aspectRatio)
|
|
|
23
64
|
return radius / math.sin(halfFov)
|
|
24
65
|
end
|
|
25
66
|
|
|
67
|
+
--[=[
|
|
68
|
+
Checks if a position is on screen on a camera
|
|
69
|
+
|
|
70
|
+
@param camera Camera
|
|
71
|
+
@param position Vector3
|
|
72
|
+
@return boolean
|
|
73
|
+
]=]
|
|
26
74
|
function CameraUtils.isOnScreen(camera, position)
|
|
27
75
|
local _, onScreen = camera:WorldToScreenPoint(position)
|
|
28
76
|
return onScreen
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
--[=[
|
|
2
|
+
Interface between user input and camera controls
|
|
3
|
+
@class CameraControls
|
|
4
|
+
]=]
|
|
3
5
|
|
|
4
6
|
local require = require(script.Parent.loader).load(script)
|
|
5
7
|
|
|
@@ -11,7 +13,7 @@ local Maid = require("Maid")
|
|
|
11
13
|
local GamepadRotateModel = require("GamepadRotateModel")
|
|
12
14
|
local InputObjectUtils = require("InputObjectUtils")
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
-- Stolen directly from ROBLOX's core scripts.
|
|
15
17
|
-- Looks like a simple integrator.
|
|
16
18
|
-- Called (zoom, zoomScale, 1) returns zoom
|
|
17
19
|
local function rk4Integrator(position, velocity, t)
|
|
@@ -175,7 +177,7 @@ function CameraControls:SetRotatedCamera(rotatedCamera)
|
|
|
175
177
|
return self
|
|
176
178
|
end
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
-- This code was the same algorithm used by Roblox. It makes it so you can zoom easier at further distances.
|
|
179
181
|
function CameraControls:_handleMouseWheel(inputObject)
|
|
180
182
|
if self._zoomedCamera then
|
|
181
183
|
local delta = math.clamp(-inputObject.Position.Z, -1, 1)*1.4
|
|
@@ -210,7 +212,7 @@ function CameraControls:_handleTouchPinch(scale, velocity, userInputState)
|
|
|
210
212
|
end
|
|
211
213
|
end
|
|
212
214
|
|
|
213
|
-
|
|
215
|
+
-- This is also a Roblox algorithm. Not sure why screen resolution is locked like it is.
|
|
214
216
|
function CameraControls:_mouseTranslationToAngle(translationVector)
|
|
215
217
|
local xTheta = (translationVector.x / 1920)
|
|
216
218
|
local yTheta = (translationVector.y / 1200)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
A CameraEffect is something that can be resolved into a CameraState providing source
|
|
3
|
+
@class CameraEffectUtils
|
|
4
|
+
]=]
|
|
5
|
+
|
|
6
|
+
--[=[
|
|
7
|
+
Represents an effect that can be used in combination with other effects.
|
|
8
|
+
@interface CameraEffect
|
|
9
|
+
.CameraState CameraState
|
|
10
|
+
@within CameraEffectUtils
|
|
11
|
+
]=]
|
|
12
|
+
|
|
13
|
+
--[=[
|
|
14
|
+
Something that is like a camera
|
|
15
|
+
@type CameraLike CameraEffect | CameraState
|
|
16
|
+
@within CameraEffectUtils
|
|
17
|
+
]=]
|
|
18
|
+
|
|
19
|
+
return {}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
--[=[
|
|
2
|
+
For effects that can be easily bound in scope
|
|
3
|
+
@class CustomCameraEffect
|
|
4
|
+
]=]
|
|
3
5
|
|
|
4
6
|
local require = require(script.Parent.loader).load(script)
|
|
5
7
|
|
|
@@ -8,8 +10,11 @@ local SummedCamera = require("SummedCamera")
|
|
|
8
10
|
local CustomCameraEffect = {}
|
|
9
11
|
CustomCameraEffect.ClassName = "CustomCameraEffect"
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
--[=[
|
|
14
|
+
Constructs a new custom camera effect
|
|
15
|
+
@param getCurrentStateFunc () -> CameraState -- Custom effect generator
|
|
16
|
+
@return CustomCameraEffect
|
|
17
|
+
]=]
|
|
13
18
|
function CustomCameraEffect.new(getCurrentStateFunc)
|
|
14
19
|
local self = setmetatable({}, CustomCameraEffect)
|
|
15
20
|
|
|
@@ -22,6 +27,12 @@ function CustomCameraEffect:__add(other)
|
|
|
22
27
|
return SummedCamera.new(self, other)
|
|
23
28
|
end
|
|
24
29
|
|
|
30
|
+
--[=[
|
|
31
|
+
The current state.
|
|
32
|
+
@readonly
|
|
33
|
+
@prop CameraState CameraState
|
|
34
|
+
@within CustomCameraEffect
|
|
35
|
+
]=]
|
|
25
36
|
function CustomCameraEffect:__index(index)
|
|
26
37
|
if index == "CameraState" then
|
|
27
38
|
return self._getCurrentStateFunc()
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
--
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
--[=[
|
|
2
|
+
Hack to maintain default camera control by binding before and after the camera update cycle
|
|
3
|
+
This allows other cameras to build off of the "default" camera while maintaining the same Roblox control scheme.
|
|
4
|
+
|
|
5
|
+
This camera is automatically setup by the [CameraStackService](/api/CameraStackService).
|
|
6
|
+
@class DefaultCamera
|
|
7
|
+
]=]
|
|
4
8
|
|
|
5
9
|
local require = require(script.Parent.loader).load(script)
|
|
6
10
|
|
|
@@ -13,6 +17,11 @@ local SummedCamera = require("SummedCamera")
|
|
|
13
17
|
local DefaultCamera = {}
|
|
14
18
|
DefaultCamera.ClassName = "DefaultCamera"
|
|
15
19
|
|
|
20
|
+
--[=[
|
|
21
|
+
Constructs a new DefaultCamera
|
|
22
|
+
|
|
23
|
+
@return DefaultCamera
|
|
24
|
+
]=]
|
|
16
25
|
function DefaultCamera.new()
|
|
17
26
|
local self = setmetatable({}, DefaultCamera)
|
|
18
27
|
|
|
@@ -25,6 +34,10 @@ function DefaultCamera:__add(other)
|
|
|
25
34
|
return SummedCamera.new(self, other)
|
|
26
35
|
end
|
|
27
36
|
|
|
37
|
+
--[=[
|
|
38
|
+
Overrides the global field of view in the cached camera state
|
|
39
|
+
@param fieldOfView number
|
|
40
|
+
]=]
|
|
28
41
|
function DefaultCamera:OverrideGlobalFieldOfView(fieldOfView)
|
|
29
42
|
self._cameraState.FieldOfView = fieldOfView
|
|
30
43
|
end
|
|
@@ -33,6 +46,13 @@ function DefaultCamera:OverrideCameraState(cameraState)
|
|
|
33
46
|
self._cameraState = cameraState or error("No CameraState")
|
|
34
47
|
end
|
|
35
48
|
|
|
49
|
+
--[=[
|
|
50
|
+
Binds the camera to RunService RenderStepped event.
|
|
51
|
+
|
|
52
|
+
:::tip
|
|
53
|
+
Be sure to call UnbindFromRenderStep when using this.
|
|
54
|
+
:::
|
|
55
|
+
]=]
|
|
36
56
|
function DefaultCamera:BindToRenderStep()
|
|
37
57
|
RunService:BindToRenderStep("DefaultCamera_Preupdate", Enum.RenderPriority.Camera.Value-2, function()
|
|
38
58
|
self._cameraState:Set(Workspace.CurrentCamera)
|
|
@@ -45,11 +65,20 @@ function DefaultCamera:BindToRenderStep()
|
|
|
45
65
|
self._cameraState = CameraState.new(Workspace.CurrentCamera)
|
|
46
66
|
end
|
|
47
67
|
|
|
68
|
+
--[=[
|
|
69
|
+
Unbinds the camera from the RunService
|
|
70
|
+
]=]
|
|
48
71
|
function DefaultCamera:UnbindFromRenderStep()
|
|
49
72
|
RunService:UnbindFromRenderStep("DefaultCamera_Preupdate")
|
|
50
73
|
RunService:UnbindFromRenderStep("DefaultCamera_PostUpdate")
|
|
51
74
|
end
|
|
52
75
|
|
|
76
|
+
--[=[
|
|
77
|
+
The current state.
|
|
78
|
+
@readonly
|
|
79
|
+
@prop CameraState CameraState
|
|
80
|
+
@within DefaultCamera
|
|
81
|
+
]=]
|
|
53
82
|
function DefaultCamera:__index(index)
|
|
54
83
|
if index == "CameraState" then
|
|
55
84
|
return rawget(self, "_cameraState")
|