Getting 2d mouse position in 3d world

let’s say I have a 2d game, and i have a system that lets the player create parts where they click, but only the x, and y positions of the part should be calculated, since its a 2d game. and there’s a invisible barrier part infront of the camera

I decide to use camera:ViewportPointToRay(mousePos.X, mousePos.Y), and then raycast using it’s origin and direction to calculate the new part’s position, but the problem is, the more far away the mouse from the center of the screen is, the more offset the new part’s position is, due to :ViewportPortToRay() being cast from the center of the screen to the mouse position, which hits the invisible barrier part, which makes it offset without using the Z position

local unitRay = camera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)

local rayResult = workspace:Raycast(unitRay.Origin, unitRay.Direction * maxDistance, rayParams)
	

I tried adding mouseLocation - (cam.ViewportSize / 2) to the mouseLocation but that didn’t fix the prolem either

I need help solving this problem


1 Like

Try using camera:ScreenPointToRay() instead of camera:ViewportPointToRay().

local userInputService = game:GetService("UserInputService")
local workspace = game:GetService("Workspace")

local camera = workspace.CurrentCamera

local rayDistance = 100
local raycastParams = RaycastParams.new()

userInputService.InputBegan:Connect(function(input, processed)
	if processed then return end
	if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
	
	local mousePosition = userInputService:GetMouseLocation()
	local ray = camera:ScreenPointToRay(mousePosition.X, mousePosition.Y)
	local result = workspace:Raycast(ray.Origin, ray.Direction * rayDistance, raycastParams)
	
	if result and result.Instance then
		print(result.Instance)
	end
end)

Didn’t work, isn’t ScreenPointToRay the same thing as viewport but with account for the gui offset?

Wouldnt something like this be possible? This uses the player’s mouse and gets the cursors CFrame in the 3D space.

local mouse = game.Players.LocalPlayer:GetMouse()
		
mouse.Button1Down:Connect(function()
	local mouseCf = mouse.Hit
	print("CFrame of mouse in 3D space: ", mouseCf)
end)
2 Likes

Add your invisible part to an ignore list in your raycast params

The invisible barrier doesn’t even matter, as you can see im clicking on nothing, which returns the unitray origin + unitray direction, and it still has the issue

See the image below. The mouse is where i clicked, the black part is where it spawned.

You could try using the Z component of the player root part’s position and the X, Y components from the raycast’s hit position.

I’m noticing you said:

Did you remember to also multiply the maxDistance to that return value? As an example the function to get the 3D position of your mouse needs to look something like this:

local function get3DMousePosition()
	local mouseLocation = UserInputService:GetMouseLocation() -- I'm assuming you named UserInputService "UserInputService" since it's not visible in the script you provided
	local ray = camera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
	local raycastResult = workspace:Raycast(ray.Origin, ray.Direction * maxDistance, rayParams)

	if raycastResult then
		return raycastResult.Position
	else
		return ray.Origin + ray.Direction * maxDistance
	end
end

Note that the return value when raycastResult is nil is ray.Origin + ray.Direction * maxDistance not just ray.Origin + ray.Direction

what are you setting the part’s position to