If you look at a SurfaceGui from an angle, you can view it at much higher distances than looking straight at it. I am wondering how I would detect if a SurfaceGui is visible, my current code just gets the distance from the center of the face to the camera.
Surface:
-- Gets face
local Face = SurfaceGui.Face
if not Face then return 0 end
-- Gets center of face
local FaceCFrame = Adornee.CFrame * CFrame.new((Adornee.Size/2)*KiwiUtility.FaceList[Face.Name])
-- Gets distance to camera
return (Camera.CFrame.Position - FaceCFrame.Position).Magnitude
Billboard:
-- Distance checks
local Distance = (Camera.CFrame.Position - WorldPosition).Magnitude
if IgnoreCovering == nil and BillboardGui.MaxDistance > 0 then
if Distance > BillboardGui.MaxDistance then return false, Vector2.new(), Distance end
end
This same issue also happens with billboards, I can’t make bug reports so I am just asking for a workaround.
SurfaceGui (this just returns the distance from the closest point on the respective surfaceGui.Face), compare this directly with surfaceGui.MaxDistance to return whether or not it’s currently visible, point would be Camera.CFrame.Position:
local function calculateDistanceFromClosestPointOnFace(point, part)
local surfaceGUi = part:WaitForChild('SurfaceGui')
local face = surfaceGui.Face
local faceVec = Vector3.fromNormalId(face)
local pointOnFace = faceVec * 0.5 * part.Size
local pointOnPart = part.CFrame * CFrame.new(pointOnFace)
local cameraLocal = pointOnPart:PointToObjectSpace(camera.CFrame.Position)
local clampedToFace = cameraLocal:Max(-0.5 * part.Size):Min(0.5 * part.Size) * (Vector3.one - faceVec:Abs()) + pointOnFace
return (point - pointOnPart:PointToWorldSpace(clampedToFace)).Magnitude
end
As for Billboard, are you using any of the offsets? That will complicate things a bit, let me know.
Longer parts can still trigger the GUI from distance using this function (the custom hover cursor is active), I need a solution that would work reliably for any SurfaceGui
And for offsets on BillboardGuis, I am using SizeOffset, StudsOffset, and StudsOffsetWorldSpace, not using extents offset. Heres my current calculations for Billboards:
-- Values
local Size = BillboardGui.AbsoluteSize
local SizeOffset = BillboardGui.SizeOffset
local StudsOffset = BillboardGui.StudsOffset
local StudsOffsetWorldSpace = Adornee.CFrame:ToWorldSpace(CFrame.new(BillboardGui.StudsOffsetWorldSpace))
-- WorldPosition
local WorldPosition = StudsOffsetWorldSpace.Position + StudsOffset
workspace.PartTest.Position = WorldPosition
-- Screen Position
local ScreenPosition = Camera:WorldToScreenPoint(WorldPosition)
-- Distance checks
local Distance = (Camera.CFrame.Position - WorldPosition).Magnitude
if IgnoreCovering == nil and BillboardGui.MaxDistance > 0 then
if Distance > BillboardGui.MaxDistance then return false, Vector2.new(), Distance end
end
I tried it on a square part, my bad. It looks like the camera’s point on the face needs to be constrained to be within the smallest of the two axes adjacent to faceVec, so this should work for determining visibility:
local function calculateDistanceFromClosestPointOnFace(point, part)
local surfaceGui = part:WaitForChild('SurfaceGui')
local face = surfaceGui.Face
local faceVec = Vector3.fromNormalId(face)
local pointOnFace = faceVec * 0.5 * part.Size
local pointOnPart = part.CFrame * CFrame.new(pointOnFace)
local cameraLocal = pointOnPart:PointToObjectSpace(point)
local smallestAxis
if faceVec.X >= 0.001 then
smallestAxis = math.min(part.Size.Y, part.Size.Z)
elseif faceVec.Y >= 0.001 then
smallestAxis = math.min(part.Size.X, part.Size.Z)
else
smallestAxis = math.min(part.Size.X, part.Size.Y)
end
local smallest = Vector3.one * smallestAxis
local clampedToFace = cameraLocal:Max(-0.5 * smallest):Min(0.5 * smallest) * (Vector3.one - faceVec:Abs()) + pointOnFace
return (point - pointOnPart:PointToWorldSpace(clampedToFace)).Magnitude
end
I decided I will make my own max distance instead of using Roblox’s “interesting” system, your function works a bit better than the one before, but I think its better to use a system that hides at the distance you set it at