Creating steady camera head bob?

So currently, I use sine to generate camera offset on the Y and X axes. However, that only moves it in one direction mainly.

If you can picture a center dot, basically the direction of the sine is it goes to the upper right side from that center dot, then as it goes down again it’ll go to the bottom left side from the origin.

This is good, but I’m trying to find a way to create ‘steady’ head bobbing, where the sine would generate a more balanced left-to-right and up-to-down look, if that makes any sense at all.

Will upload a quick video when I get the chance, might help show what I mean.

Thank you :slight_smile:

1 Like

I don’t know for sure if my idea will work, but using two sine functions (one for x, one for y) and running them slightly offset from each other.

2 Likes

Yep, the above reply is actually a great way to go about this.
Have an offset on the horizontal axis and an offset on the vertical axis and have them intervene.

For example consider the figure-eight curve, also known as Lemniscate of Gerono
8-figure-curve

This is written by:

x = cos(t)
y = sin(2*t) / 2

However, this is limited to a fixed horizontal and vertical amplitude so you change that by multiplying the sin and cos equations by some amount, to create an amplitude respective to both.

x = cos(t) * 10
y = sin(2*t) * 10

Lemniscate of Gerono Curve

But if you wanted to just use sine then you can do like so:
Obviously you can tweak this around, i.e add a dilation, etc, just figure what works for you.

y = 2sin(2t) * 1
x = 4sin(t) * 1

Sine curve

Other curvy stuff:
Lemniscate of Bernoulli
Watt’s curve

So I guess just experiment with different curves until you find one that works for you. Hopefully I’m not misunderstanding you. Would be helpful to get some visuals :slight_smile:

Example
local frequency = 5
local horizantalAmplitude = .2
local verticalAmplitude = .2
local deltaTime = 0

local player = game:GetService('Players').LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild('Humanoid')

function Update(delta)	
	deltaTime += delta
	if humanoid.MoveDirection.Magnitude > 0  then
		local horizontalOffset = math.sin(deltaTime * frequency * 2) * horizantalAmplitude
		local verticalOffset = math.sin(deltaTime * frequency) * verticalAmplitude
        -- Create an offset on both x and y axis using a proportional ratio
		local bobble = Vector3.new(horizontalOffset, verticalOffset, 0)
		humanoid.CameraOffset = humanoid.CameraOffset:Lerp(bobble, .5)
	end
end

game:GetService('RunService').RenderStepped:Connect(Update)

6 Likes