CameraScreenPointToRay is inaccurate?


local function fire()
	local bulletSpread = tool:GetAttribute("BulletSpread")
	local mouseLocation = UserInputService:GetMouseLocation()
	local unitRay = currentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y + GuiService:GetGuiInset().Y)
	local raycastResult = Workspace:Raycast(tool.Handle.Position, unitRay.Direction * 100)
	local intersection = raycastResult and raycastResult.Position or tool.Handle.Position + unitRay.Direction * 100
	local distance = (tool.Handle.Position - intersection).Magnitude
	local bulletTracer = Instance.new("Part")
	bulletTracer.Size = Vector3.new(0.15, 0.15, distance)
	bulletTracer.CFrame = CFrame.lookAt(tool.Handle.Position, intersection) * CFrame.new(0, 0, -distance/2)
	bulletTracer.Anchored = true
	bulletTracer.Parent = Workspace
end

I’m trying to replace mouse.Hit.Position in my gun system using screenPointToRay, but I just cant figure out how to get it to work properly? (Also ignore some of the messy code)


Here, the image above shows my actual mousePosition, and where the bulletTracer shows it hits?

2 Likes

ViewportPointToRay() already accounts for the gui inset. You don’t need to add it any further.

I feel like it’s a bit more accurate now, but It feels like theres some weird offset thing that I’m just not accounting for and im not sure what it is

This may sound stupid and may contradict my previous reply but try subtracting the GUI inset from the Y position. It may work.



It works slightly better (??), but when it comes to shooting at a low angle (2nd image) it doesnt give me the results im hoping for

local function fire()
	local bulletSpread = tool:GetAttribute("BulletSpread")
	local mouseLocation = UserInputService:GetMouseLocation()
	local unitRay = currentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y - GuiService:GetGuiInset().Y)
	local raycastResult = Workspace:Raycast(tool.Handle.Position, unitRay.Direction * 100)
	local intersection = raycastResult and raycastResult.Position or tool.Handle.Position + unitRay.Direction * 100
	local distance = (tool.Handle.Position - intersection).Magnitude
end

What did this look like with the cursor on the baseplate


When I dont do anything with the gui inset, here’s what it looks like:
local unitRay = currentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)

Oh, I thought I was on to something for a moment.

Can you try making a visualizer part at the positions? This may help.

1 Like


local hitPart = Instance.new("Part")
	hitPart.Size = Vector3.new(0.5, 0.5, 0.5)
	hitPart.Position = intersection
	hitPart.Anchored = true
	hitPart.CanCollide = false
	hitPart.BrickColor = BrickColor.new("Really red")
	hitPart.Material = Enum.Material.Neon
	hitPart.Shape = Enum.PartType.Ball
	hitPart.Parent = Workspace

I believe your problem comes from the fact that the raycast origin is the tool and not the camera. Its only going to appear correct if the part starts at the camera, because the direction created by the unitRay is relative to the camera, not the tool.

1 Like

Yea, that’s what I was thinking, but my goal is to make it look like it comes from the handle (it will be polished later, but im just testing), any ideas on how to fix this offset?

I think the easiest way is to raycast twice: Once to get whatever the hit position is at the center of the screen, and once to see if the tool could hit that position from its own position.

If there isnt an initial hit position at the center of the screen, then the tool could just use a best guess angle to raycast towards, which doesnt seem like a big deal since you are likely aiming at the sky at that point.

I am sure there is a more complex way you could figure this out with math, but I dont know it.

Okay, Ill experiment with this, thanks for your help

Sorry, try this:

local tool = script.Parent
local UserInputService = game:GetService("UserInputService")
local currentCamera = workspace.CurrentCamera

local plr = game:GetService("Players").LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()

local function makeP(p)
	local hitPart = Instance.new("Part")
	hitPart.Size = Vector3.new(0.5, 0.5, 0.5)
	hitPart.Position = p
	hitPart.Anchored = true
	hitPart.CanCollide = false
	hitPart.BrickColor = BrickColor.new("Really red")
	hitPart.Material = Enum.Material.Neon
	hitPart.Shape = Enum.PartType.Ball
	hitPart.Parent = workspace
	game:GetService("Debris"):AddItem(hitPart,5)
end

local params = RaycastParams.new()
params.FilterDescendantsInstances = {char}

local function fire()
	local mouseLocation = UserInputService:GetMouseLocation()
	local unitRay = currentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
	local mouseHitRay = workspace:Raycast(unitRay.Origin, unitRay.Direction * 100,params)
	local endPos = mouseHitRay and mouseHitRay.Position or unitRay.Origin + unitRay.Direction * 100
	local raycastResult = workspace:Raycast(tool.Handle.Position, endPos-tool.Handle.Position,params)
	local intersection = raycastResult and raycastResult.Position or endPos
	local distance = (tool.Handle.Position - intersection).Magnitude
	local bulletTracer = Instance.new("Part")
	bulletTracer.Size = Vector3.new(0.15, 0.15, distance)
	bulletTracer.CFrame = CFrame.lookAt(tool.Handle.Position:Lerp(intersection,0.5), intersection)
	bulletTracer.Anchored = true
	makeP(intersection)
	makeP(unitRay.Origin)
	makeP(tool.Handle.Position)
	makeP(endPos)
	bulletTracer.Parent = workspace
	game:GetService("Debris"):AddItem(bulletTracer,5)
end

tool.Activated:Connect(fire)
1 Like

From what I’ve tested, this works!

Yes, now, please mark my post as the solution.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.