How to get CFrame of head and CFrame of controllers for VR

Within a modulescript

local VRService = game:GetService("VRService")
local cam = workspace.CurrentCamera

local vrControl = {}

--@outline get_left_controller_world_cframe
-- This gets the CFrame of the left contproller
function vrControl.get_left_controller_world_cframe(): CFrame
	local handOffset = VRService:GetUserCFrame(Enum.UserCFrame.LeftHand)
	-- Account for headscale
	handOffset = handOffset.Rotation + handOffset.Position * workspace.CurrentCamera.HeadScale
	
	if not cam.HeadLocked then
		handOffset = vrControl.get_head_offset():ToObjectSpace(handOffset)
	end

	return workspace.CurrentCamera.CFrame * handOffset
end

------------------------------------------------------------------------------------

--@outline get_right_controller_world_cframe
-- This gets the CFrame of the right controller
function vrControl.get_right_controller_world_cframe(): CFrame
	
	local handOffset = VRService:GetUserCFrame(Enum.UserCFrame.RightHand)
	-- Account for headscale
	handOffset = handOffset.Rotation + handOffset.Position * workspace.CurrentCamera.HeadScale

	if not cam.HeadLocked then
		handOffset = vrControl.get_head_offset():ToObjectSpace(handOffset)
	end
	
	return workspace.CurrentCamera.CFrame * handOffset
end

------------------------------------------------------------------------------------

--@outline get_head_offset
-- This gets the head offset in studs
function vrControl.get_head_offset(): CFrame
	local headOffset = VRService:GetUserCFrame(Enum.UserCFrame.Head)
	if not cam.HeadLocked then
		return headOffset
	end
	-- Account for headscale
	return headOffset.Rotation + headOffset.Position * workspace.CurrentCamera.HeadScale
end


--@outline get_head_world_cframe
-- This gets the CFrame of the head
function vrControl.get_head_world_cframe(): CFrame
	if not cam.HeadLocked then
		return workspace.CurrentCamera.CFrame
	end
	return workspace.CurrentCamera.CFrame * vrControl.get_head_offset()
end

return vrControl

These functions allows getting the world cframe, and also accounts for if headlocked is set to false (for more sophisticated scripting)

To get the world CFrames of the headset and the arms:

local vrcontrol = require(path.to.vrcontrol.module)

local head_cf = vrcontrol.get_head_world_cframe()
local left_controller_cf = vrcontrol.get_left_controller_world_cframe()
local right_controller_cf = vrcontrol.get_right_controller_world_cframe()
3 Likes

You can use this data to also detect when the VR CoreGUI menu is visible or not based upon the position from the bottom bar:

bottom_bar_distance_threshold =  2.3 -- if exceeds this threshold, assume that the menu is closed

local camera = workspace.CurrentCamera
local panelpartfolder = camera:WaitForChild("VRCorePanelParts")
local bottomBar = panelpartfolder:WaitForChild("BottomBar_Part")

local bottom_bar_position_reached = (head_cf.Position - bottomBar.Position).Y > bottom_bar_distance_threshold
if bottom_bar_position_reached then
 print("Menu is closed")
else
 print("Menu is open")
end

1 Like