ViewModel animation rotation

When I play an animation, I want my viewmodel to rotate with the animation as well instead of just staying in place.

I can’t seem the figure out how to do it, the closest thing I can find to doing it is using runservice and locking the camera to the head which makes the animation and all rotations play correctly but then you can’t move your mouse at all

I looked for solutions on HiddenDevs, searched up tutorials, asked friends, looked on the devforum and I am yet to find a solution for it

if input.KeyCode == Enum.KeyCode.R then
			vmRun:Disconnect()
			reloadAnimation:Play()
			shootCooldown = true
			vmAnimRun = runService.RenderStepped:Connect(function()
				fingersVM.PrimaryPart.CFrame = camera.CFrame
			end)
			reloadAnimation.Ended:Connect(function()
				shootCooldown = false
				idleAnimation:Play()
				vmAnimRun:Disconnect()
				vmRun = runService.RenderStepped:Connect(function()
					fingersVM.PrimaryPart.CFrame = camera.CFrame
				end)
			end)
		end

The first video is of a game which has the same mechanic and the 2nd video is what happens when I try using renderstepped to lock the camera, works perfectly fine but I can’t move the character nor the camera to look around,



Now this is what happens when I don’t renderstep the currentcamera to the head:

1 Like

Can you explain what you exactly mean by wanting your ViewModel to “rotate” with the animation?

(I’m sorry I’m like a bit confused still by what you mean by that)

Sorry I must’ve really confused you,


This video shows what happens when I don’t renderstep the viewmodel’s head to the camera, it just plays the animation without the head moving and I want the animation from the head to play on the currentcamera, (so basically adding the movement and rotation from the animation that it played on the head to the camera) If I renderstep the currentCamera to the head, it plays but I can’t move the camera around nor can I move my character around or else it will renderstep from the last known position of the viewmodel and only after the animation has finished will then go back to the characters position because of the renderstep being disconnected.

1 Like

If by viewmodel rotating you mean just rotating the currentcamera to match the movement (not direction) of your character’s head, then I would do just that:

Have a function play each frame with a variable describing the previous frame’s head orientation. In the current frame, identify the difference in the previous head orientation and the current head orientation, then apply that offset to the currentcamera.

This should move the camera in the same direction and magnitude as the head, but you would still be able to move and look in another directions.

Sorry I can’t provide sample code, but I hope this idea can be of some help

1 Like

So basically would it just be like:

local previousHeadRotation = fingersVM:WaitForChild("Head").CFrame - fingersVM:WaitForChild("Head").CFrame.Position
			
			runService.RenderStepped:Connect(function()
				local currentHeadRotation = fingersVM:WaitForChild("Head").CFrame - fingersVM:WaitForChild("Head").CFrame.Position
				
				local rotationDelta = previousHeadRotation:Inverse() * currentHeadRotation
				
				camera.CFrame = camera.CFrame * rotationDelta
				previousHeadRotation = currentHeadRotation
			end)

?

1 Like

I think so, as long as the CurrentCamera.CameraType is custom and not scriptable, the player should be able to move their camera while the animation is playing

Tip

basepart.CFrame.Rotation
will return a CFrame with only orientation and no translation

I’ve done something similar to this! I hope my explanation can help you!

Above your RenderStepped function add a nil variable called oldCFrame.
Then in your RenderStepped function, add this:

local camBone = vm:FindFirstChild("CameraBone")
if camBone then
	local newCamCF = camBone.CFrame:ToObjectSpace(vm.PrimaryPart.CFrame)
	if oldCFrame ~= newCamCF then
		Camera.CFrame *= newCamCF:ToObjectSpace(oldCFrame)
	end
	oldCFrame = newCamCF
end

You can just replace the variables for the viewmodel and camera part/head of the viewmodel.
What this does is that it offsets the camera the same way the camera part is offset from the Primary Part of the viewmodel.

And when you pivot or change the CFrame of the Viewmodel, do this:

vm:PivotTo(
	Camera.CFrame *
		(
			oldCFrame:Inverse()
		)
)

If we don’t add the inverse of the camera offset onto the viewmodel, then it will make what I believe is a “feedback loop” where the camera constantly gets offset by the viewmodel, then the viewmodel adjusts to the camera, then offsets the camera again. With this, we just eliminate that loop.

Hope this helps!

1 Like

Thing is, the ViewModel is just a duplication of the starter character with the arms and head only which means the head is the primaryPart and the head is the animated part.

vmRun:Disconnect()
			reloadAnimation:Play()
			shootCooldown = true
			local oldCFrame
			
			vmAnimRun = runService.RenderStepped:Connect(function()
				fingersVM.PrimaryPart.CFrame = camera.CFrame
				local camBone = fingersVM:FindFirstChild("Head")
				
				if camBone then
					local newCamCF = camBone.CFrame:ToObjectSpace(fingersVM.PrimaryPart.CFrame)
					
					if oldCFrame ~= newCamCF then
						camera.CFrame *= newCamCF:ToObjectSpace(oldCFrame)
					end
					
					oldCFrame = newCamCF
				end
			end)

And it just errors saying:

Players.Player.Backpack.Gun.GunScript:105: invalid argument #2 (CFrame expected, got nil)

Maybe changing the camerasubject to the animated head could work

Your viewmodel doesn’t have an HRP?