Trying to highlight an object based on mouse position and cant fix an offset

  1. What do you want to achieve? Keep it simple and clear!
    I need to highlight an object for a character customizer (just working on the highlighting at the moment)

  2. What is the issue? Include screenshots / videos if possible!






    pretty simply, ive got it to set a highlight based on what the mouse is pointing at but there is a major offset that seems?? to change when the camera rotates

  3. What solutions have you tried so far? Did you look for solutions on the Creator Hub?
    changed how it sees what the mouse is pointing at (currently using raycast- it doesnt look like the offset changes depending on what method i use though)

RunService.Heartbeat:Connect(function(delta)
    local mousePosition = UserInputService:GetMouseLocation()
    local mouseX = mousePosition.X
    local mouseY = mousePosition.Y

    local ray = camera:ViewportPointToRay(mouseX, mouseY)
    local raycastParams = RaycastParams.new()
    raycastParams.FilterDescendantsInstances = {}
    raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
    raycastParams.IgnoreWater = true

    local result = Workspace:Raycast(ray.Origin, ray.Direction * 1000, raycastParams)
    if result and result.Instance then
        local target = result.Instance
        if target:GetAttribute("IsItem") == true then
            highlight.Adornee = target
        else
            highlight.Adornee = nil
        end
    else
        highlight.Adornee = nil
    end 
end)

above is my code (not including the basic defining parts- if those need to be included as well do tell me) and im honestly at a loss for where to go from here

Well, I just slightly changed your script to target any part and added the variables I needed to get your code to work and I’m getting no offset at all. Works perfectly. (my only real change to your logic was instead of checking “IsItem” I just check if target then

strange? ill try that, if the isitem thing is the issue im gonna be so angry :sob: it was my placeholder for a lot of things needed

The only thing I can think of (which seems super unlikely) is if you somehow have the wrong camera, or if you somehow overwrite the highlight elsewhere. The change I made should have no effect on the script.

hm. actually. would this potentially be because of the things im highlighting being meshes? with how offset it is i dont think its likely but it just came to mind

It may be. I think raycasting uses the collision shape, and collision shapes often are wrong because it’s expensive to match a mesh, so you have to change the collision mesh to the precise mode otherwise it may actually just be a box.

I guess the property is called collision fidelity

The problem is the ray-to-mouse highlight is offset and shifts with the camera rotation

You are building the ray with raw GetMouseLocation pixels, but that includes the GUI inset, (top bar) so the ray isn;'t actually aligned to the 3D view, when the camera moves the mismatch looks like a drifting/rotating offset

Here’s how to fix it, pretty simple:
use camera:ScreenPointToRay(x, y) (it handles insets).
or ubtract the inset before ViewportPointToRay
So:

local p = UserInputService:GetMouseLocation() - game:GetService("GuiService"):GetGuiInset()
local ray = workspace.CurrentCamera:ViewportPointToRay(p.X, p.Y)

Update on the RENderStopped frame, not the Heartbeat, set the highlight.Adornee to a BASEPART or a FindFirstAncestorWhichIsA(“MOdel”) if you want the whole model
Also, blacklist LocalPlayer.Character and UI/FX parts to avoid any false hits, that’ll hopefully remove the offset

It shouldn’t be. GetMouseLocation() doesn’t take the inset into account, but niether does :ViewportPointToRay() so it should cancel out. Also it worked perfectly on my system when I tested it.

neither of those ended up workign unfortunately. only other thing i can think of is that the player is a bit off from everything i need to highlight due to how ive got it set up, would that mess with it?

Would you be comfortable sending more of the code? I don’t think the problem is the snippet you sent.

local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local UserInputService = game:GetService("UserInputService")

local highlight = game:GetService("ReplicatedStorage"):WaitForChild("Highlight")
local camera = Workspace.CurrentCamera

RunService.Heartbeat:Connect(function(delta)
    local mousePosition = UserInputService:GetMouseLocation()
    local mouseX = mousePosition.X
	local mouseY = mousePosition.Y
	local p = UserInputService:GetMouseLocation() - game:GetService("GuiService"):GetGuiInset()

	local ray = workspace.CurrentCamera:ViewportPointToRay(p.X, p.Y)
    local raycastParams = RaycastParams.new()
    raycastParams.FilterDescendantsInstances = {}
    raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
    raycastParams.IgnoreWater = true

    local result = Workspace:Raycast(ray.Origin, ray.Direction * 1000, raycastParams)
    if result and result.Instance then
        local target = result.Instance
        if target then
            highlight.Adornee = target
        else
            highlight.Adornee = nil
        end
    else
        highlight.Adornee = nil
    end
end)

entire script so far

Huh. I guess that’s probably not going to really change much. Honestly the only thing I can think of is if you are changing the camera at some point (never even tried changing the current camera myself). If you do change the camera to another instance though it won’t update the camera since you set it once out of the loop.

I will also note the only time it didn’t work was when I tested the collision fidelity which gave me an offset for the meshes at lower fidelities

1 Like
local RS = game:GetService("RunService")
local UIS = game:GetService("UserInputService")
local GS  = game:GetService("GuiService")
local cam = workspace.CurrentCamera
local player = game.Players.LocalPlayer

-- one Highlight in Workspace
local hl = (workspace:FindFirstChild("DebugHighlight") or Instance.new("Highlight"))
hl.Name = "DebugHighlight"
hl.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop
hl.Parent = workspace

-- tiny red debug dot
local dot = (workspace:FindFirstChild("RayDot") or Instance.new("Part"))
dot.Name, dot.Anchored, dot.CanCollide, dot.Size, dot.Color, dot.Material =
    "RayDot", true, false, Vector3.new(0.2,0.2,0.2), Color3.new(1,0,0), Enum.Material.Neon
dot.Parent = workspace

RS.RenderStepped:Connect(function()
    local p = UIS:GetMouseLocation() - GS:GetGuiInset()           -- viewport coords
    local ray = cam:ViewportPointToRay(p.X, p.Y)                   -- or use ScreenPointToRay with NO inset

    local params = RaycastParams.new()
    params.FilterType = Enum.RaycastFilterType.Blacklist
    params.FilterDescendantsInstances = {player.Character, hl}     -- avoid self hits

    local res = workspace:Raycast(ray.Origin, ray.Direction * 2000, params)
    if not res then hl.Adornee = nil return end

    dot.CFrame = CFrame.new(res.Position)
    hl.Adornee = res.Instance                                     -- EXACT part hit
end)

Try this, if the red dot is where the cursor hits but the white outline is offset, it’s a adorneee pivot issue
So try hl.Adornee = res.Instance only (no parent model)

If you need the whole model, fix pivots first:model:PivotTo(model:GetPivot()), or highlight a dedicated hitbox part.

Now, if the red dot itself is off it is a camera/ mouse timing, do you have a custom camera?

And what comes to my head:

  1. Parent the highlight to workspace, not left in RS
  2. Racast blacklist includes FX/UI and the player
  3. Skinned meshes can have weird bounds, so just highlight a simple part when possible
1 Like

image
well, this is enlightening at the least. i do not have a custom camera, unless you mean changing the camera subject / having the camera type be custom (although the image is with the camera simply set to orbital with a different focus than the player)

1 Like

Well… That offset is suspicious and it might somehow be this. That’s an offset I would expect from an inset problem

1 Like

ok so yeah since the red dot itself is offet, that means its a ray build issue, not the actual highlight, with a orbital camera, use screen cords, not the viewport, try this exact swap:

RS.RenderStepped:Connect(function()
    local cam = workspace.CurrentCamera
    local p = UIS:GetMouseLocation()            -- NO inset subtraction
    local ray = cam:ScreenPointToRay(p.X, p.Y)  -- ScreenPointToRay handles insets

    local params = RaycastParams.new()
    params.FilterType = Enum.RaycastFilterType.Blacklist
    params.FilterDescendantsInstances = {player.Character}

    local res = workspace:Raycast(ray.Origin, ray.Direction*2000, params)
    dot.CFrame = res and CFrame.new(res.Position) or dot.CFrame
    hl.Adornee = res and res.Instance or nil
end)

and, if it still drifts do a baseline check using th eengine picker:

local m = player:GetMouse()
RS.RenderStepped:Connect(function()
    if m.Target then
        dot.CFrame = CFrame.new(m.Hit.Position)   -- should sit under cursor
    end
end)

Now:

  1. If GetMouse().Hit is correct but the ray isn’t that means it’s a camera/coord math error, keep the ScreenPointToRay and do not subtract the inset
  2. If GetMouse().Hit is also offset, something is intercepting, bad, like a mouse locked center, a customer cursor scaling, or some sort of UI/ViewportFrame overaly, also make sure the Hightlight is parented to the Workspace and again very important blacklist your character and any FX parts
1 Like

just to double check- if the ray isnt working correctly is there anything im supposed to be changing? its a little late im having truble understanding mb

So:
If the ray itself isnt lining up (red dot from earlier is off) you only need to change one thing in the code:
swap ViewportPointToRay for ScreenPointToRay and remove the inset subtraction.
That fixes the offset caused by camera types like Orbital.

Here:

local p = UserInputService:GetMouseLocation()
local ray = camera:ScreenPointToRay(p.X, p.Y)

And if that still doesnt work try this:

local mouse = game.Players.LocalPlayer:GetMouse()
print(mouse.Hit.Position)

If that hit matches where youre pointing, the problem isnt the ray anymore its something else, but most of the time, so 90%, switching to ScreenPointToRay solves it, so just pray that it’s the first

2 Likes