And then we say this i donât know why :
lastCameraCF = camera.CFrame
The code works by figuring out how the camera has rotated since the previous (âlastâ, I prefer the less ambiguous âpreviousâ) frame. It does that by comparing the âcurrentâ CF to the previous CF, so it needs to store the âold/previous/lastâ CF for the next frame. It does that after itâs done processing the current frame, otherwise it would be pointless
When we use local rot = camera.CFrame:ToObjectSpace(lastCameraCF)
doesnât it mean that rotâs orientation becomes the opposite direction of our camera so why donât we look at our back with this?
doesnât it mean that rotâs orientation becomes the opposite direction of our camera
No, rot
becomes lastCameraCF
but relative to camera.CFrame
. In other words, "the transformation from camera.CFrame
to lastCameraCF
". Since lastCameraCF
is the CFrame of the camera at the previous frame, rot
becomes the transformation from the previous frameâs CF to the current frameâs CF. Or âhow the camera has moved since the last frameâ. Well, itâs really the inverse of that because the original programmer flipped the arguments but oh well. Iâm a bit confused RN by the double negatives, but i think that explains why the original programmer had to have a negative swayAMT
. transform
would be a way better variable name, or even better transformFromPrevFrame
.
After the assignment, camera.CFrame == lastCameraCF * rot
holds true. Another statement that illustrates what I mean (a and b are Parts):
print(a.CFrame * a.CFrame:ToObjectSpace(b.CFrame) == b.CFrame) --Always true
so why donât we look at our back with this?
Not sure what you meant by this or âopposite direction of the cameraâ, sorry. If you explain that in more detail maybe I can help clear it up, but maybe itâs not needed.
It takes the inverse of the cameraâs transformation from the last frame (rot
) (inverse because of the flipped arguments I mentioned earlier) and turns that into Euler angles, which is a way of representing orientation or rotation in the way youâre used to from the properties window. âX, Y, Zâ angles or preferably âpitch, yaw, rollâ angles which is usually clearer Aircraft principal axes - Wikipedia
In the line below, we rotate an empty CFrame with these variables with every rendered frame.
swayCF = swayCF:Lerp(CFrame.Angles(math.sin(X) * swayAMT, math.sin(Y) * swayAMT, 0), 0.1)
Do you mean swayCF
is âemptyâ? Itâs only empty on the first frame, on subsequent frames itâs whatever it was set to on the previous frame. Do you mean that the CF constructed with CFrame.Angles
is âemptyâ? Well itâs clearly not since itâs being constructed with non-zero parameters.
Itâs not entirely accurate to say that swayCF
gets rotated by these variables. After all, the line doesnât say something like swayCF *= CFrame.Angles(blablabla)
. Itâs more like it gets set to a specific orientation, which would be accurate if it werenât for the Lerp call which just smooths out the movement which is absolutely necessary because mouse movement is super jittery. Plus it makes it look like the viewmodel has momentum.
Setting the sway to an orientation that follows the rotation (âmovementâ but for orientation) of the camera causes the viewmodel to âleadâ where the camera is pointing.
Looking closely at it, I think itâs a mistake to use math.sin
in this case. The fastest I was able to rotate the camera in an experiment was about 0.6 radians. Call it 1.0 to be generous. Hereâs x
and sin(x)
plotted in [-1;1]
:
As you can see, theyâre pretty close so having the sin
call in there doesnât do a lot. It does kind of reduce the output a bit at the extreme ends, so it could be a valid approach to make the sway not go beyond a certain limit even with extreme camera movement. But the effect is so small I donât think itâs worth the confusion, and it doesnât work at even more extreme movements:
At inputs outside [-pi/2; pi]
, sin
starts moving the wrong direction! So if you move the camera move than 90 degrees in a frame, the sway goes in the opposite direction?! Not sure if thatâs the intentional, artistic choice of the original programmer but I donât think thatâs a good idea. First, itâs confusing to read compared to just math.clamp and takes all this analysis to figure out, second it doesnât have much effect in the domain thatâs usually relevant, so itâs very little gain for a decent amount of technical debt, and third it kinda breaks in edge cases. Iâd remove it and just have this instead:
swayCF = swayCF:Lerp(CFrame.Angles(X * swayAMT, Y * swayAMT, 0), 0.1)
In my earlier response I said some things about math.sin
, theyâre still true but donât really apply in this situation. I didnât fully understand back then what it was doing in the code, sorry if my response caused any confusion.
What is the point of this code ? In the first rendered frame, we will use camera.CFrame:ToObjectSpace()
on a empty CFrame (lastCameraCF)
Again, ToObjectSpace
works on TWO CFrames, not just one. So that LoC doesnât do it âon a CFâ, it does it on a pair of CFs. The camera CFrame is probably not empty, so the computation probably actually does do something. Even if it didnât do anything to the camera CF, it would still have a purpose because it sets lastCFrame
so something can actually happen on the next frame. To be fair itâs a tiiiny bit confusing that the original programmer set lastCameraCF
to CFrame.new()
at the top of the script, because thatâs not a sensible âfirst previousâ CFrame. A version that fixes this could look like
RunS.RenderStepped:Connect(function()
--If this is the first frame then there's no sensible way of computing the sway, so just set the variable for next frame and pretend like there has been no movement since the last frame ("previous = current").
_previousCameraCF = _previousCameraCF or camera.CFrame
local rot = ... everything else like it was
end)
This shows a clear intent for how the sway should be handled in the edge case where there is no âpreviousâ frame. This actually fixes minor a bug too, itâs not just just about coding style but thinking clearly about what the code does so good job spotting that thereâs something weird. What happens if the player spawns in with a camera thatâs yawed 179 degrees? Theyâll get a massive spike of sway on the first frame, causing the viewmodel to jerk a bit to the left or right. It wonât be too extreme or even noticable because itâs just for a single frame and then it quickly falls back to a normal state but hey a bug is a bug Another benefit is that thereâs no ugly state variable at the top of the script (I mean you could have it but I wouldnât). A down side is that itâs still a global variable that might get accidentally set by a different function. Thereâs loads of ways to âcaptureâ that variable in a block so only the relevant code can see it, but this is already a big of a tangent, sorry xD
BTW the a = a or b
thing might look a bit confusing at first and you could argue that it is, but itâs idiomatic (common) Lua so experienced coders will quickly recognize that itâs a way of providing a default value in situations where a value isnât already provided.
is it used for not swaying when we donât move, right ? Because if we donât move, camera.CFrame
wonât change so X,Y,Z values will be 0.
No, none of this code has anything to do with how the camera translates though space (X, Y, Z coordinates, from walking and stuff), only with how the camera rotates (from mouse movement, or touch or controller or VR or whatever). If you try walking but not moving the mouse you should see no sway at all. Thatâs why I donât think X, Y and Z are good variable names in this case. Pitch, yaw and roll would make it clearer that itâs talking about rotation and not translation.
The ToOrientation
call completely ignores the position component of the input CFrame, so if the camera moved a bit to the left or w/e that has no effect on the sway. You could use the same approach to make a âwalk swayâ though. Itâd be a great challenge to see how well you understand all this stuff.
Anyway hope this wall of text helps clear some things up xD And I hope I got everything right Ask away if you have follow up questions