Problem with ray direction

I have a ray that is supposed to go from the barrel of a gun to the mouse cursor. However, the ray direction is kind of malformed since it is directly the direction from the camera. I need the direction to go towards the mouse location from a barrel instead of the camera.

How would I do this?

What the function to create the ray looks like:

local function XYtoRay(x, y) 
	local unitRay = camera:ViewportPointToRay(x, y)
	local calculateDist = (camera.CFrame.Position - barrel.Position).Magnitude + 250 -- 250 is the normal distance
	return Ray.new(barrel.Position, unitRay.Direction * calculateDist)
end

I am using an InputObject’s position for the X & Y value (ContextActionService binded function third parameter). Changing to :ScreenPointToRay also did not help.

Due to my direction not being compatible with the barrel position, this creates rays that look like they skip through objects even though they’re not due to a weird direction.

Attempt

I tried to do unitRay.Origin + unitRay.Direction * calculateDist to get a goal end point that I could use with the barrel position to get a proper direction but it only made it worse.

Failed attempt
local function XYtoRay(x, y) 
	local unitRay = camera:ViewportPointToRay(x, y)
	local calculateDist = (camera.CFrame.Position - barrel.Position).Magnitude + 250
	local goal = unitRay.Origin + unitRay.Direction
	local dir = (barrel.Position - goal).Unit * calculateDist
	return Ray.new(barrel.Position, dir)
end

This is not working properly because unitRay.Direction is the direction from the CAMERA to the target

You can try using this

local function RayToMouse()
	local calcDir = (Mouse.Hit.Position-barrel.Position).Unit
	return Ray.new(barrel.Position, calcDir*100) -- 100 is the depth of the ray
end

Edit: Removed the X, Y, unnecessary

1 Like

I’ve already stated this into my post by the way (just not specifically):

I don’t use Mouse.Hit because the Mouse object is superseded by UserInputService and InputObjects but your solution does work.

Would me doing one raycast to get the end result position then using it similarly to how Mouse.Hit.Position is used in your code work as well?

local unitRay = camera:ViewportPointToRay(x, y)
local _, pos = workspace:FindPartOnRay(Ray.new(unitRay.Origin, unitRay.Direction * 250), char) -- ignore character
local barrelPos = barrel.Position
local calcDirec = (pos - barrelPos ).Unit * 250
return Ray.new(barrelPos, calcDirec)

Sorry but i couldn’t understand

I’ve edited it but basically to use it the same way you did with Mouse.Hit.Position except with a finished raycast position instead to replace it. (For an alternative solution without the Mouse object)

I think you could try this

local function PosToRay(X, Y, Depth)
	local ray = camera:ViewportPointToRay(X, Y, Depth) -- If it still works weird try camera:ScreenPointToRay
	local hit, pos = workspace:FindPartOnRay(ray)
	local calcDir = (pos - barrel.Position)
	return Ray.new(barrel.Position, calcDir*Depth)
end

Edit: Changed from RayToMouse to PosToRay

1 Like

I don’t think you have to multiply calcDir by Depth since the ray is already giving you that depth.

Also, using the Depth argument on :ViewportPointToRay or :ScreenPointToRay ruins the ray’s direction for some reason so I just resort to multiplying the ray direction by the depth instead for a ray direction.

:ViewportPointToRay is most weird with the mouse so I use :ScreenPointToRay

local function XYtoRay(X, Y)
	local Depth = 250
	local ray = camera:ViewportPointToRay(X, Y)
	ray = Ray.new(ray.Origin, ray.Direction * Depth)
	local _, pos = workspace:FindPartOnRay(ray, char)
	local calcDir = (pos - barrel.Position)
	return Ray.new(barrel.Position, calcDir)
end

This result works just like the Mouse.Hit.Position version so this is the most effective way to go about it without the Mouse object.

Full version
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()

local Depth = 250
local function XYtoRay(X, Y)
	local ray = camera:ScreenPointToRay(X, Y) -- use this for the mouse
	ray = Ray.new(ray.Origin, ray.Direction * Depth)
	local _, pos = workspace:FindPartOnRay(ray, char)
	local calcDir = (pos - barrel.Position) -- no need to turn into .Unit form
	return Ray.new(barrel.Position, calcDir)
end

EDIT: For PC-only, you could also use UserInputService:GetMouseLocation() instead of an InputObject’s position X & Y value and then skip the X, Y parameters.

Im extremely confused, why need the camera??

The camera uses the functions :ViewportPointToRay() or :ScreenPointToRay() which are useful to create a ray that from the camera goes to the mouse/touch position.


This is usually the best way to get something similar to Mouse.Hit.Position but without the Mouse object I think. UserInputService:GetMouseLocation() is also a similar option to use in combination with these functions to get the mouse hit position but I don’t think it’s compatible for non-PC platforms.

1 Like