Holographic sight WorldToViewportPoint SurfaceGui incorrect offset

  1. What do you want to achieve? Keep it simple and clear!
    I want to make holographic-type sights in my weapon framework

  2. What is the issue? Include screenshots / videos if possible!
    My holographic scope offset doesn’t render properly after my changes to the viewmodel script. The scope offsets vertically fine, but bugs horizontally.
    The scope is a SurfaceGui on a part welded to the scope model which is welded to the main gun handle.
    The gun is welded to the character via a Motor6D with Part0 set to the character’s torso, which is created a little bit after the gun is equipped; the default “RightGrip” tool weld is removed.
    Arms and the weapon’s Motor6D get their C0 changed depending on if the weapon is currently scoped in or not in the UpdateCharacter function

Before:

After:

How the scopes get binded to render

RunService:BindToRenderStep("WeaponScopeRender", Enum.RenderPriority.Last.Value + 1, function(dt)
	for _, Config in ipairs(self.AimPoints) do
		task.spawn(Config.Update, Config, dt)
	end
end)

Scope update function

function module:Update(dt)
	local ScopeEnabled = Viewmodel.FirstPerson and Viewmodel.Aiming

	self.ReticleContainer.Surface.Enabled = ScopeEnabled
	
	if Viewmodel.CurrentAimPoint == self.AimPoint then
		shared["CameraFOVs"][self.AimPoint] = 1 - (1 - (self.AimPoint:GetAttribute("FOVMultiplier") or 0.9)) * Viewmodel.AimSpring.Position
	end
	
	if not ScopeEnabled then
		return
	end
	
	local Scale = self.ReticleContainer.CFrame:PointToObjectSpace(Camera.CFrame.Position) / self.ReticleContainer.Size
	local ScopePosition = Camera:WorldToViewportPoint(self.ReticleContainer.Position)

	pcall(function()
		self.EyeRelief.Container.Position = UDim2.new(0.5 - Scale.X * (self.AimPoint:GetAttribute("LensSensitivity") or 1), 0, 0.5 - Scale.Y * (self.AimPoint:GetAttribute("LensSensitivity") or 1), 0)
	end)
	
	pcall(function()
		self.Reticle.Container.Position = UDim2.new(0.5, ScopePosition.Y - Camera.ViewportSize.Y / 2, 0.5, -(ScopePosition.X - Camera.ViewportSize.X / 2))
	end)
	
	local Amount = math.clamp(Viewmodel.AimSpring.Position, 0, 1)
	for Part, Transparency in self.InvisibleParts do
		Part.Transparency = Transparency * (1 - Amount) + 1 * Amount
	end
end

How first person gets binded

local TimePassed = 0
RunService:BindToRenderStep("PlayerCharacterPointer", Enum.RenderPriority.Character.Value + 1, function(dt)
	TimePassed += dt

	if Player.Character then
		module:UpdateCharacter(Player.Character, Result, 5 * dt)
		Player.Character["Right Arm"].LocalTransparencyModifier = 0
		Player.Character["Left Arm"].LocalTransparencyModifier = 0
	end
end)
  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve tried changing the RenderPriority to be lower or higher but that seemed to not affect it at all