Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local Player = game.Players.LocalPlayer
- local Screen = script.Parent
- local Camera = workspace.CurrentCamera
- local FieldOfView = Camera.FieldOfView --//will be abbreviated as FOV when paired with other words (e.g. MyFOV)
- local XY_FOV_RATIO = .7 --//The X and Y axis do not both cover 70 degrees, so this scales it down
- --//returns four vectors in a table such that:
- --//table.x = [x lower bound lookvector, x upper bound lookvector]
- --//table.y = [y lower bound lookvector, y upper bound lookvector]
- --//input cameraDirection is the camera CFrame, fieldOfView is the Field of View in radians
- local function GetCameraBoundsInCameraSpace(fieldOfView)
- local RadianHalfFOV = math.rad(fieldOfView*.5)
- --//Finds all the lookVector camera bounds via rotation
- local LowerCameraBoundY = CFrame.Angles( RadianHalfFOV,0,0).lookVector
- local UpperCameraBoundY = CFrame.Angles(-RadianHalfFOV,0,0).lookVector
- --//Y is straight foreward because FOV is based off of it, we have to
- --//do some modifications for X though
- local ScaleFromYtoX = Screen.AbsoluteSize.X/Screen.AbsoluteSize.Y
- local UpperCameraBoundYHeight = UpperCameraBoundY.Y
- local UpperCameraBoundYDepth = UpperCameraBoundY.Z
- local UpperCameraBoundXSize = UpperCameraBoundYHeight*ScaleFromYtoX
- local LowerCameraBoundX = Vector3.new(-UpperCameraBoundXSize,0,UpperCameraBoundYDepth).unit
- local UpperCameraBoundX = Vector3.new( UpperCameraBoundXSize,0,UpperCameraBoundYDepth).unit
- local X_FOVAngle = math.deg(2*math.atan(UpperCameraBoundXSize/UpperCameraBoundYDepth)) --simply 2tan^-1(y/x)
- return {
- X = {["Lower"] = LowerCameraBoundX, ["Upper"] = UpperCameraBoundX};
- Y = {["Lower"] = LowerCameraBoundY, ["Upper"] = UpperCameraBoundY};
- X_FOV = X_FOVAngle;
- Y_FOV = fieldOfView; --//Also returns field of view for math purposes
- }
- end
- --//returns a normalised vector projected onto an object-space plane on the camera
- local function ProjectVectorOntoCameraPlane(cameraDirection, vectorPointingToPart, plane)
- local ProjectedVector --//vectorPointingToPart projected onto plane
- local CameraObjectSpaceVector;
- --//essentially the X component on the screen
- if plane == "XZ" then
- CameraObjectSpaceVector = cameraDirection:vectorToObjectSpace(vectorPointingToPart)
- ProjectedVector = Vector3.new(CameraObjectSpaceVector.x,0,CameraObjectSpaceVector.z) --//removes Y component so the vector becomes 2D on XZ
- --//essentially the Y component on the sreen
- elseif plane == "YZ" then
- CameraObjectSpaceVector = cameraDirection:vectorToObjectSpace(vectorPointingToPart)
- ProjectedVector = Vector3.new(0,CameraObjectSpaceVector.y,CameraObjectSpaceVector.z) --//removes Z component so the vector becomes 2D on XY
- end
- return ProjectedVector.unit
- end
- --//returns a normalized vector pointing from from to to (heh)
- local function PointToVector3(from, to)
- return (to-from).unit
- end
- --//returns angles between vectors in degrees
- local function FindDegreesBetweenVectors(vector1, vector2)
- return math.deg(math.acos(vector1.unit:Dot(vector2.unit)))
- end
- --//returns Absolute X and Absolute Y positions of a 3D position
- local function ObtainScreenPositionFrom3DPosition(position, camera, fieldOfView)
- local ObjectIsOutsideOfScreenBounds = false
- local AbsoluteXPosition;
- local AbsoluteYPosition;
- --//General X and Y position stuff
- local DirectionToPartFromCamera = PointToVector3(camera.CoordinateFrame.p,position)
- local CameraBounds = GetCameraBoundsInCameraSpace(fieldOfView) --//this can be moved outside the function and achieve the same effect
- local FieldOfViewAlongXAxis = CameraBounds.X_FOV
- local FieldOfViewAlongYAxis = CameraBounds.Y_FOV --//the same as fieldOfView ALWAYS
- --//Finding the approximate X pixel value
- local PartDirectionInCameraSpaceXZ = ProjectVectorOntoCameraPlane(camera.CoordinateFrame, DirectionToPartFromCamera, "XZ")
- local AngleFromLowerBoundX = FindDegreesBetweenVectors(CameraBounds.X.Lower, PartDirectionInCameraSpaceXZ)
- local AngleFromUpperBoundX = FindDegreesBetweenVectors(CameraBounds.X.Upper, PartDirectionInCameraSpaceXZ)
- if AngleFromLowerBoundX <= FieldOfViewAlongXAxis and AngleFromUpperBoundX <= FieldOfViewAlongXAxis then --//if it doesn't extends beyond the degrees in the FOV
- AbsoluteXPosition = (AngleFromUpperBoundX / FieldOfViewAlongXAxis) * Screen.AbsoluteSize.X --//basically ratio of way across screen (yes, scale!) * #pixels
- else
- ObjectIsOutsideOfScreenBounds = true
- end
- --//Finding the approximate Y pixel value
- local PartDirectionInCameraSpaceXY = ProjectVectorOntoCameraPlane(camera.CoordinateFrame, DirectionToPartFromCamera, "YZ")
- local AngleFromLowerBoundY = FindDegreesBetweenVectors(CameraBounds.Y.Lower, PartDirectionInCameraSpaceXY)
- local AngleFromUpperBoundY = FindDegreesBetweenVectors(CameraBounds.Y.Upper, PartDirectionInCameraSpaceXY)
- if AngleFromLowerBoundY <= FieldOfViewAlongYAxis and AngleFromUpperBoundY <= FieldOfViewAlongYAxis then --//if it doesn't extends beyond the degrees in the FOV
- AbsoluteYPosition = (AngleFromLowerBoundY / FieldOfViewAlongYAxis) * Screen.AbsoluteSize.Y --//basically ratio of way across screen (yes, scale!) * #pixels
- else
- ObjectIsOutsideOfScreenBounds = true
- end
- return ObjectIsOutsideOfScreenBounds and Vector2.new(0,0) or Vector2.new(AbsoluteXPosition, AbsoluteYPosition)
- end
- --//main body ok
- local function main()
- local GUIThing = Instance.new("Frame",Screen)
- GUIThing.Size = UDim2.new(0,5,0,5)
- while wait() do
- local cameraBounds = GetCameraBoundsInCameraSpace(FieldOfView)
- --//moves a GUI around to cover 0,0
- local XYPos = ObtainScreenPositionFrom3DPosition(Vector3.new(0,0,0),Camera,FieldOfView)
- if XYPos ~= Vector2.new(0,0) then
- GUIThing.Visible = true
- GUIThing.Position = UDim2.new(0,XYPos.X,0,XYPos.Y)
- else
- GUIThing.Visible = false
- end
- end
- end
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement