Set gui element's position to a part in a viewport frame?

so i have a character in a simulation inside of a viewport frame. i want to place a gui marker on the humanoidrootpart, but i cant get the X value to update correctly. as far as i can tell, the problem is that the marker doesn’t respect depth between the camera and the character; if you think about it, it would be behaving perfectly if the character walked past the camera at 0 distance.

my code for positioning the marker:

--viewCam = the camera
--clonedModel.Character = the character
--charCursor = the marker frame (its just a frame rotated by 45 degrees)

local vec = viewCam:WorldToViewportPoint(clonedModel.Character.PrimaryPart.Position)
local screenSize = viewCam.ViewportSize
local vec2 = Vector2.new(vec.X * screenSize.X,vec.Y * screenSize.Y)
print(vec.Y,screenSize.Y,vec.Y*screenSize.Y)
charCursor.Visible = cursorEnabled
charCursor.Position = UDim2.new(vec.X,0,vec.Y,0)

a video of the behavior:
robloxapp-20200409-1416213.wmv (278.8 KB)

thank you for your time

1 Like

vec contains absolute pixel coordinates, so you should use the Offset property of X and Y in your UDim2, not Scale…

Your last line should be:
charCursor.Position = UDim2.new(0, vec.X, 0, vec.Y)

Additionally, vector math is a thing, so you can just (as long as you convert vec to a Vector2):

local vec2 = vec * screenSize

I can also trim out some unnecessary parts, since WorldToViewportPoint returns offsets, not scale:

local vec = viewCam:WorldToViewportPoint(clonedModel.Character.PrimaryPart.Position)
charCursor.Visible = cursorEnabled
charCursor.Position = UDim2.new(0, vec.X, 0, vec.Y)

I think you might mean, if you really meant to use scale, this:

local vec = viewCam:WorldToViewportPoint(clonedModel.Character.PrimaryPart.Position)
local screenSize = viewCam.ViewportSize
local scale = Vector2.new(vec.X, vec.Y) / screenSize
charCursor.Visible = cursorEnabled
charCursor.Position = UDim2.new(scale.X, 0, scale.Y, 0)

it’s the same result. i’m currently multiplying the scale by the size in pixels of the viewport frame, which is the same thing.

it’s creating a scale value out of vec, which is what im already doing. just tested it and it does indeed result in the same thing. my problem here is that it does not involve the depth value. if i could make it move slower the farther away it is (like how a distant object moves “slower” compared to your total field of view) i would be home free.

But you aren’t using the scale value you create (vec2), you are setting the position to vec.X and vec.Y (In your last line in your first post)

Except your code doesn’t work, and mine does.

You’re talking about parallax. WorldToViewportPoint accounts for this (field of view and all). You should be fine.

yes, parallax. forgot the word, thank you. i insist i tried your code and it was the exact same- i predicted it would be, since, like i said, the end results of each are the same numbers.

Both code snippets I provided create the exact same end result because they are two alternate methods of solving the same problem. The code you originally posted doesn’t work because you’re multiplying by the viewport size and not dividing. You’re also creating the UDim2 from vec and not vec2.

The first method is probably the best method to solve what your root problem was, which is positioning a 2D GUI object over a 3D point in space. The second one is closer to the code you had in the original post, intentionally using scale instead of offset, but it does the same thing as the first and is slightly slower (but not significantly so).

just noticed, happy birthday.

this is the result of the first method- Position = UDim2.new(0,vec.X,0,vec.Y
image
notice how they are scale values, for some reason. that is why i used them as scale.

Does my code create an incorrect result? I made it in the Discourse textbox.

it does. my current code:

local vec = viewCam:WorldToViewportPoint(clonedModel.Character.PrimaryPart.Position)
print(vec)
charCursor.Visible = cursorEnabled
charCursor.Position = UDim2.new(0,vec.X,0,vec.Y)

printing vec returns the values above. X and Y are, for whatever reason, scale values. putting them in offset rounds them down and it moves one pixel once the value reaches 1, which happens somewhere on the bottom right side of the screen.

This sounds like a bug. I’ve used this function before and I’ve never had that happen. Additionally, the documentation says otherwise. Would you care to make a bug report?

i suppose. it just feels weird… ive never encountered a bug before, and this seems deliberate. the scale values are aligned with the character. if the character is in the middle, its on it. if they move, it moves a little faster and de-syncs. yes, though, i will make a bug report.

Before you do so-

Are you using the ViewportFrame’s CurrentCamera, and not the player’s? And what point are you using?

im not using viewport.CurrentCamera, but im 101% that viewCam is the camera it is set to. not for a moment does it change. the point is the characters primarypart position, .PrimaryPart.Position.

Okay, good. You should be good to file a bug report, since everything else seems to be in order.

i actually don’t think this is a bug. Both WorldToViewportPoint and WorldToScreenPoint are based on the camera’s viewport size property and since you can’t change it and it defaults to 1,1 this leads to those methods not always (usually) working as you expected it to (return the “correct” position in pixels). The Workspace camera’s viewport size is always the actual size of the player’s viewport (in pixels) because the core scripts set it to such , which is why it works there . So, what i would do is create a custom function to do the conversion, for example you should be able to use one of the functions ego moose provided here:

Also, At the bottom of the viewportframe release thread, this is talked about a little bit( and there is a function or two there):


Overall, i don’t really think this is a bug ( i could be wrong of course), but if it isn’t then i think you might want to make a feature request instead.

Oh! If the camera’s viewport size is actually (1, 1) then I guess only my second snippet would work, but it should work.

1 Like

thankfully, its not critical that i have this feature. im going to go ahead and abandon the concept and save myself the headache. ill mark this as the solution because it’s useful to anyone in the future who actually requires this behavior. thank you all for the help!

1 Like