Camera:WorldToScreenPoint() returning less than 1 for x and y, not correct scale either

This is the script i am using

	local Vector = Object.Adornee.Parent.Parent.CurrentCamera:WorldToScreenPoint(Rig.PrimaryPart.Position)
	print(Vector)
	Effect.Position = UDim2.fromScale(Vector.X , Vector.Y)
	Effect.Parent = SelfCreature.Adornee:FindFirstAncestorWhichIsA("ScreenGui")

The Rig’s PrimaryPart is the red cube.

If i print vector i getr less than 1 for x and y, so i set the gui objects position with scale, which yields unaccurate results.

I find it particularly odd since this function is supposed to return an offset value, which is an integer, does the fact that the camera is in a viewport change anything?

I think you might have accidentally made two threads.

The code works fine for me:

1 Like

Oh i forgot i made that one xd, which one do i delete?
I just realised i cant delete it .-.

1 Like

I don’t think you can since, thanks to me, they both have replies. Don’t worry about it.

Maybe its the fact that i run this code with a viewport.

I think the discrepancy is that WorldToScreenSpace is trying to transform that position onto your main screen rather than one of the viewport’s size. I have no clue how to set up a viewport and I’m late for work, but give this a go. Courtesy of Stravant and his ancient ScreenSpace module.
You need to define viewport and camera

function WorldToScreen(at)
	local point = camera.CoordinateFrame:pointToObjectSpace(at)
	local aspectRatio = viewport.AbsoluteSize.X/viewport.AbsoluteSize.Y
	local hfactor = math.tan(math.rad(camera.FieldOfView)/2)
	local wfactor = aspectRatio*hfactor
	--
	local x = (point.x/point.z) / -wfactor
	local y = (point.y/point.z) /  hfactor
	--
	return Vector2.new(viewport.AbsoluteSize.X*(0.5 + 0.5*x), viewport.AbsoluteSize.Y*(0.5 + 0.5*y))
end

It’s also a module worth checking out, even nowadays it has some cool stuff in it. For example, you can use it to get the size of a part required to fill the whole screen at a certain distance away.

5 Likes

Interesting problem, and I can confirm it works. @boyparis mark @JarodOfOrbiter as the answer.

image

---replace viewport with your viewportFrame
---replace camera with viewportCamera
local vector = WorldToScreen(part.Position)
frame.Position = UDim2.fromOffset(vector.X,vector.Y)--parented under viewport frame

Replication code
Taken from viewport GUI article:

Insert local script into screen gui in starter gui
local viewportFrame = Instance.new("ViewportFrame")
viewportFrame.Size = UDim2.new(0.3, 0, 0.4, 0)
viewportFrame.Position = UDim2.new(0, 15, 0, 15)
viewportFrame.BackgroundColor3 = Color3.new(0, 0, 0)
viewportFrame.BorderColor3 = Color3.new(0.6, 0.5, 0.4)
viewportFrame.BorderSizePixel = 2
viewportFrame.BackgroundTransparency = 0.25
viewportFrame.Parent = script.Parent

local part = Instance.new("Part")
part.Material = Enum.Material.Concrete
part.Color = Color3.new(0.25, 0.75, 1)
part.Position = Vector3.new(0, 0, 0)
part.Parent = viewportFrame

local viewportCamera = Instance.new("Camera")
viewportFrame.CurrentCamera = viewportCamera
viewportCamera.Parent = viewportFrame

viewportCamera.CFrame = CFrame.new(Vector3.new(0, 2, 12), part.Position)

wait(1)
local vector = viewportCamera:WorldToScreenPoint(part.Position)
print(vector)


function WorldToScreen(at)
	local point = viewportCamera.CoordinateFrame:pointToObjectSpace(at)
	local aspectRatio = viewportFrame.AbsoluteSize.X/viewportFrame.AbsoluteSize.Y
	local hfactor = math.tan(math.rad(viewportCamera.FieldOfView)/2)
	local wfactor = aspectRatio*hfactor
	--
	local x = (point.x/point.z) / -wfactor
	local y = (point.y/point.z) /  hfactor
	--
	return Vector2.new(viewportFrame.AbsoluteSize.X*(0.5 + 0.5*x), viewportFrame.AbsoluteSize.Y*(0.5 + 0.5*y))
end

local frame = Instance.new("Frame")
frame.BackgroundColor3 = Color3.fromRGB(51, 255, 37)
frame.AnchorPoint = Vector2.new(0.5,0.5)
frame.BackgroundTransparency = 0.5
frame.Size = UDim2.fromOffset(100,100)
frame.Parent = viewportFrame

local vector = WorldToScreen(part.Position)
frame.Position = UDim2.fromOffset(vector.X,vector.Y)

Yeah, this will do for now, thanks. :shallow_pan_of_food:
Weird how the X position never goes above 1 despite me moving the part.


This is definitely further to the right than half a pixel
I don’t understand.

Also, this still is not working for me, the effect shows up in the wrong position ofr some reason.

The issue with the original world to screen point was the new camera Camera.ViewportSize.

When you create a new camera the view port size is only 1,1

image

Vs the normal one which is dependent on the current window size

image

Consequently, this is why you are getting the low values for vector XY according to what WorldToScreenPoint/Viewport does.

Consequently, using fromScale should actually work because of the ratios for example.

But since you still have the issue although I believe it works from my replication code, you should check where the frames are parented and such as they can effect Position as well and also your model PrimaryPart is in the right position.

1 Like

So if i change the camera’s viewportsize to the frame’s size the position would match? i will try that.