Position attachment to 2D point on camera

I have been stuck on this for about the last hour and a half, and it is the only thing stopping me.

Basically I want to get the 3D world position from a point on the camera. I have tried ViewportPointToRay, and it has always ended up above the camera somehow?

This is my code:

local function NewPoint(point: CFrame)
		local p = Instance.new("Attachment",Host)
		p.WorldCFrame = point
		p.Name = `{tostring(point.X)}, {tostring(point.Y)}, {tostring(point.Z)}`
		p.Visible = true
	end
	
	local function GenerateGrid()
		local CamRes = camera.ViewportSize
		repeat
			CamRes = camera.ViewportSize
			task.wait()
		until CamRes.X > 1 and CamRes.Y > 1

		local squareSize = math.min(CamRes.X,CamRes.Y)/resolution
		
		for x = 1, CamRes.X, squareSize do
			for y = 1, CamRes.Y, squareSize do
				local scaleX, scaleY = x / CamRes.X, y / CamRes.Y
				
				local worldPos = camera:ViewportPointToRay(x, y).Origin
				
				NewPoint(CFrame.new(worldPos))
			end
		end
	end

This is the result:

Yes I have tried using CFrame and WorldCFrame on the attachment.

have you tried ScreenPointToRay and make sure you are setting the direction and a long enough length that the ray hits something in the 3d space… by default viewportpointtoray is only 1 stud in length so if using it will also need to increase the length and make sure it hits something

this is also explained on the ViewportPointToRay hub info

I have tried ScreenPointToRay, and it does the same. It also would not work for what I need. I only need the origin of the ray, so I’m not sure I need to increase the ray length.

I have tested this with screenpoint and viewportpoint using origins and even some depth and it works fine… you can see it with this simple code and an anchored part in replicated storage set size to .1 and maybe color red… this code will select random spots on the screen to get origin of then spawns the parts for visual.

it seems it maybe working maybe because you have no depth they are very close together try adding some depth to the cast so it shift the origin out from the camera some

local camera = workspace.CurrentCamera
for i = 1 , 100 do 
	local x = math.random(1,camera.ViewportSize.X)
	local y = math.random(1,camera.ViewportSize.Y)
	
	local length = 1
	local unitRay = camera:ViewportPointToRay(x, y,1)  -- this will put it out just 1 stud from camera base so they are not put together in bunch right at camera..
	--local unitRay = camera:ScreenPointToRay(x, y)  -- no depth keep at origin
	
	local extendedRay = Ray.new(unitRay.Origin, unitRay.Direction * length)
	
	local part = game.ReplicatedStorage.Part:Clone()
	part.Position = unitRay.Origin
	--part.Position = extendedRay.Origin
	part.Parent = workspace
	task.wait(.1)
end

here is code like your using 5 and 10 depth on the viewportpoint or screenpoint (only difference is the 36 offset pixels with screenpoint)

task.wait(2)

local camera = workspace.CurrentCamera
local CamRes = camera.ViewportSize

local squareSize = math.min(CamRes.X,CamRes.Y)/50

print(squareSize)

for x = 1, CamRes.X, squareSize do
	for y = 1, CamRes.Y, squareSize do
		local scaleX, scaleY = x / CamRes.X, y / CamRes.Y
		local worldPos = camera:ScreenPointToRay(x, y, 10).Origin
		
		
		local p = Instance.new("Attachment",workspace.SpawnLocation)
		p.WorldCFrame = CFrame.new(worldPos)
		p.Name = 'test' --{tostring(worldPos.X)}, {tostring(worldPos.Y)}, {tostring(worldPos.Z)}
		p.Visible = true
	end 
end

it producing attachment setups like this. first 2 are 5 res and i zoomed out to show


this is 50 res viewport


this is 50 res screenpoint

I have tried what you said, and this is what I ended up getting:


(50 Res, 10 Depth)

for x = 1, CamRes.X, squareSize do
			for y = 1, CamRes.Y, squareSize do				
				local worldPos = camera:ScreenPointToRay(x, y, 10).Origin

				NewPoint(CFrame.new(worldPos))
			end 
		end

whats the full code on this one?