Accurate crosshair spread no matter the angle

  1. What do you want to achieve?
    I want to achieve an accurate depiction of where the bullets will land using a crosshair.

  2. What is the issue?
    The issue comes from the fact I have no idea how to change the size of the crosshair according to the camera’s position and the position of where the bullets originate from.

The issue is clearly visible in the two provided images below:

Third person:
image

First person:
image

The 4 bricks that are meant to show the spread are accurately positioned in first person (since that’s where the bullets originate from), but in third person the crosshair is obviously seen not showing the position accurately.

  1. What solutions have you tried so far?
    I’ve tried looking for solutions on the web and in the forums but did not find it.
    And I also tried getting the ratio between the camera to hit distance and origin to hit distance and multiply it by that, but it didn’t work either.

Here is the piece of code that handles visualizing the spread:

local distancePerPixel = mouse.ViewSizeY/camera.FieldOfView
local spreadToUse = bloomSize
local amountToOffset = distancePerPixel*spreadToUse
		
crosshairFrame.Position = UDim2.fromOffset(mouse.X,mouse.Y)
crosshairTop.Position = UDim2.new(0.5,0,0.5,-amountToOffset)
crosshairBottom.Position = UDim2.new(0.5,0,0.5,amountToOffset)
crosshairRight.Position = UDim2.new(0.5,amountToOffset,0.5,0)
crosshairLeft.Position = UDim2.new(0.5,-amountToOffset,0.5,0)
1 Like

After a long while of experimenting, I discovered something that will help with coming up with a solution!
I found a formula(?) that gets me a radius around the center point where the spread will hit.

math.tan(math.rad(5))*(origin-target).Magnitude*2

This formula(?) if applied to a sphere part’s size and setting it’s position to the target, we will get an accurate spread, which will give us a physical visual of how big the crosshair’s spread should be.
If anyone is looking to help me, I hope this discovery may help you find a solution to my problem! <3

Edit: Also just to make sure to add: the ratio between the camera’s position and origin’s position to the target isn’t the solution!

Edit2: Here’s what I mean by a sphere part’s size:
image
The red highlighted sphere is the part I sized to the given formula.

Update: Even more discovery has been made.
I am pretty sure I need to find the angle a based on this picture:


We can use the previously found formula as the A length, C length is the distance between the camera and the target, I am just having trouble finding the right formula to test this theory!

I can now happily announce I did it!

and this is the crosshair piece of code for anyone to use:

local cameraCFrame = camera.CFrame
local camRay = camera:ScreenPointToRay(mouse.X,mouse.Y,0)
local mouseCFrame = (CFrame.new(camRay.Origin)*cameraCFrame.Rotation):ToObjectSpace(cameraCFrame)
local camPos = Vector2.new(mouseCFrame.Position.X,mouseCFrame.Position.Y)
local distanceA = math.sqrt(camPos.X^2+camPos.Y^2)
local zDistance = -camera.NearPlaneZ
		
local originP = (humanoidRootPart.CFrame*CFrame.new(0,1.5,0)).Position
local cameraP = cameraCFrame.Position
local targetP = mouse.Hit.Position
		
local cameraA = math.tan(math.rad(bloomSize))*(originP-targetP).Magnitude
local cameraB = (cameraP-targetP).Magnitude
		
local distancePerPixel = mouse.ViewSizeY/camera.FieldOfView
local spreadToUse = math.deg(math.atan(cameraA/cameraB))
		
local amountToOffset = distancePerPixel*spreadToUse*(math.sqrt(distanceA^2+zDistance^2)/zDistance)
		
crosshairFrame.Position = UDim2.fromOffset(mouse.X,mouse.Y)
crosshairTop.Position = UDim2.new(0.5,0,0.5,-amountToOffset)
crosshairBottom.Position = UDim2.new(0.5,0,0.5,amountToOffset)
crosshairRight.Position = UDim2.new(0.5,amountToOffset,0.5,0)
crosshairLeft.Position = UDim2.new(0.5,-amountToOffset,0.5,0)

Edit: Also if anyone is interested:
I’ll be making this into a open-source module script for free use after I’m finished with making the my gun system!

1 Like

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