Hi there! I finally got the motivation to figure out a solution.
I did a little research and found that holographic sights have a focal point, basically where the reticle will appear to the user.
To do this in Roblox you basically have to find the intersection of a vector from your camera to the glass of your holographic sight.
You could either do this with raycasting, but I found a better solution using trigonometry.
By drawing the normal vector of the glass, we can get 2 similar triangles
Note that we can get x by projecting the vector from the middle of the glass to the camera onto the normal vector, in Roblox this will look like
local Projection = Normal * (GlassToCam.Magnitude * (GlassToCam.Unit:Dot(Normal)))
local ProjToCamera = GlassToCam-Projection
Let the focal distance be f
the projection magnitude to be m,
the distance from the projection vector to the camera to be c
and the distance from the intersection to the center of the glass to be y
Similar triangles show that
The offset of the intersection will be
This is my code in roblox
local FocalDisance = 10
local Camera = workspace.Camera
local function GetSightOffset(Glass) --Get the intersection of a line from the focal point to the camera on the scope glass
local GlassToCam = (Camera.CFrame.Position - Glass.CFrame.Position)
local Normal = Glass.CFrame.LookVector
local Projection = Normal * (GlassToCam.Magnitude * (GlassToCam.Unit:Dot(Normal))) --Projection of glass to camera to glass normal
local ProjToCamera = GlassToCam-Projection
local OffsetMag = (ProjToCamera.Magnitude * FocalDisance)/(FocalDisance + Projection.Magnitude) --Get distance to line intersection by similair triangles
local Offset = ProjToCamera.Unit * OffsetMag
return Offset
end
local function UpdateSightPosition(Sight,Offset) --My solution to converting the offset into a Udim2 because I have little clue how they work
local StudX = Sight.Size.x
local StudY = Sight.Size.y
local Retical = Sight.SurfaceGui.Frame.Retical
Retical.Position = UDim2.new(-Offset.X/StudX,0,-Offset.Y/StudY,0)
end
local TestSight = workspace.Sight
local FocalInt = Instance.new("Part")
FocalInt.Anchored = true FocalInt.CFrame = TestSight.CFrame * CFrame.new(0,0,FocalDisance) FocalInt.Size = Vector3.new(1,1,1) FocalInt.Parent = workspace
while true do UpdateSightPosition(TestSight,GetSightOffset(TestSight)) game:GetService("RunService").RenderStepped:Wait() end
The code looks something like this
I haven’t tested this on a smaller reticle, but I’m happy with the results. If I decide to make any improvements when I finish my FPS framework I will be sure to update this post
If you have any suggestions or questions, please comment. (though I don’t check the forum very consistently)