I am trying to crop out a ViewportFrame by the front face of a part using a bunch of frames parented to each other and rotating each to cut from each edge of the part.
I have the rotation bit down but I ran into a problem with ClipsDescendants.
If the rotation of a Frame is NOT equal to 0 then ClipsDescendants does nothing. This includes a rotation of 360 degrees which probably means that this is intentional.
Here is my script. I know it’s a complete mess but I wanted to first get the script done before writing and finalizing my final product:
Script
local scrGui = script.Parent.ScreenGui
local bbGui = script.Parent.BillboardGui
local function scrSize()
return scrGui.AbsoluteSize
end
local function get3DBounds(part)
local ctr = part.CFrame*(workspace.CurrentCamera.CFrame-workspace.CurrentCamera.CFrame.p)
local box = {}
for xm=-1, 1, 2 do
for ym=-1, 1, 2 do
for zm=-1, 0, 1 do
local v = Vector3.new(0.5, 0.5, 0.5)*Vector3.new(xm, ym, zm)*part.Size
local cf = ctr*CFrame.new(v.X, v.Y, v.Z)
local pos = workspace.CurrentCamera:WorldToScreenPoint(cf.p)
table.insert(box, pos)
end
end
end
return unpack(box)
end
local function abolutize(frm)
local frm2 = Instance.new("Frame")
frm2.BackgroundTransparency = 1
frm2.Size = UDim2.new(1, 0, 1, 0)
local par = frm.Parent
frm2.Rotation = -par.AbsoluteRotation
frm.Parent = frm2
frm2.Parent = par
end
local function getFramesForBounds(a, b, c, d)
--[[local yA = math.min(a.Y, b.Y, c.Y, d.Y)
local yB = math.max(a.Y, b.Y, c.Y, d.Y)
local xA = math.min(a.X, b.X, c.X, d.X)
local xB = math.max(a.X, b.X, c.X, d.X)
local y2A = math.max(yA-a.Y, yA-b.Y, yA-c.Y, yA-d.Y)]]
--[[local p1 = Vector2.new(xA, yA)
local p2 = Vector2.new(xB, yA)
local p3 = Vector2.new(xA, yB)
local p4 = Vector2.new(xB, yB)]]
--[[local fr1 = Instance.new("Frame")
fr1.Size = UDim2.new(0, xB-xA, 0, yB-yA)
fr1.Position = UDim2.new(0, xA, 0, yA)]]
local topLeft
local topRight
local bottomLeft
local bottomRight
local pts = {a, b, c, d}
local leftMost
local rightMost
local topMost
local bottomMost
local leftMost2
local rightMost2
local topMost2
local bottomMost2
for _, pt in ipairs(pts) do
if not leftMost then
leftMost = pt
end
if not rightMost then
rightMost = pt
end
if not topMost then
topMost = pt
end
if not bottomMost then
bottomMost = pt
end
if pt.X <= leftMost.X then
leftMost2 = leftMost
leftMost = pt
end
if pt.X >= rightMost.X then
rightMost2 = rightMost
rightMost = pt
end
if pt.Y <= topMost.Y then
topMost2 = topMost
topMost = pt
end
if pt.Y >= bottomMost.Y then
bottomMost2 = bottomMost
bottomMost = pt
end
end
if topMost.X < topMost2.X then
topLeft = topMost
topRight = topMost2
else
topRight = topMost
topLeft = topMost2
end
if bottomMost.X < bottomMost2.X then
bottomLeft = bottomMost
bottomRight = bottomMost2
else
bottomRight = bottomMost
bottomLeft = bottomMost2
end
--[[for _, pt in ipairs(pts) do
if not topLeft then
topLeft = pt
end
if not topRight then
topRight = pt
end
if not bottomLeft then
bottomLeft = pt
end
if not bottomRight then
bottomRight = pt
end
if pt.X < topLeft.X and pt.Y < topLeft.Y then
topLeft = pt
end
if pt.X > topRight.X and pt.Y < topRight.Y then
topRight = pt
end
if pt.X < bottomLeft.X and pt.Y > bottomLeft.Y then
bottomLeft = pt
end
if pt.X > bottomRight.X and pt.Y > bottomRight.Y then
bottomRight = pt
end
end]]
local top = Vector2.new(topLeft.X/2+topRight.X/2, topLeft.Y/2+topRight.Y/2)
local bottom = Vector2.new(bottomLeft.X/2+bottomRight.X/2, bottomLeft.Y/2+bottomRight.Y/2)
local left = Vector2.new(topLeft.X/2+bottomLeft.X/2, topLeft.Y/2+bottomLeft.Y/2)
local right = Vector2.new(topRight.X/2+bottomRight.X/2, topRight.Y/2+bottomRight.Y/2)
local angleLeft = math.atan2(topLeft.Y-left.Y, left.X-topLeft.X)--math.atan2(bottomLeft.Y-topLeft.Y, topLeft.X-bottomLeft.X)
local angleRight = math.atan2(topLeft.Y-right.Y, right.X-topLeft.X)--math.atan2(bottomRight.Y-topRight.Y, topRight.X-bottomRight.X)
local angleTop = math.atan2(topLeft.Y-top.Y, top.X-topLeft.X)--math.atan2(topLeft.Y-topRight.Y, topLeft.X-topRight.X)
local angleBottom = math.atan2(topLeft.Y-bottom.Y, bottom.X-topLeft.X)--math.atan2(bottomLeft.Y-bottomRight.Y, bottomLeft.X-bottomRight.X)
local trans = 1
local frmLeft = Instance.new("Frame")
frmLeft.Size = UDim2.new(1, 0, 1, 0)
frmLeft.Rotation = math.deg(angleLeft)
frmLeft.Position = UDim2.new(0, topLeft.X, 0, topLeft.Y)
frmLeft.ClipsDescendants = true
frmLeft.BackgroundTransparency = trans
local frmRight = Instance.new("Frame")
frmRight.Size = UDim2.new(1, 0, 1, 0)
frmRight.Parent = frmLeft
abolutize(frmRight)
frmRight.Rotation = math.deg(angleRight)
frmRight.Position = UDim2.new(0, topRight.X-topLeft.X, 0, topRight.Y-topLeft.Y)
frmRight.ClipsDescendants = true
frmRight.BackgroundTransparency = trans
frmRight.BackgroundColor3 = Color3.new(1, 0, 0)
local frmTop = Instance.new("Frame")
frmTop.Size = UDim2.new(1, 0, 1, 0)
frmTop.Parent = frmRight
abolutize(frmTop)
frmTop.Rotation = math.deg(angleTop)
frmTop.Position = UDim2.new(0, topLeft.X-topRight.X, 0, topLeft.Y-topRight.Y)
frmTop.ClipsDescendants = true
frmTop.BackgroundTransparency = trans
frmTop.BackgroundColor3 = Color3.new(0, 1, 0)
local frmBottom = Instance.new("Frame")
frmBottom.Size = UDim2.new(1, 0, 1, 0)
frmBottom.Parent = frmTop
abolutize(frmBottom)
frmBottom.Rotation = math.deg(angleBottom)
frmBottom.Position = UDim2.new(0, 0, 0, 0)
frmBottom.ClipsDescendants = true
frmBottom.BackgroundTransparency = trans
frmBottom.BackgroundColor3 = Color3.new(0, 0, 1)
return frmLeft, frmBottom
end
local frame = scrGui.ViewportFrame
local cropF = bbGui.Frame
local crop = cropF:Clone()
local subj = bbGui.Adornee
local crop2, btm
game:GetService("RunService").RenderStepped:Connect(function()
if crop2 then
frame.Position = UDim2.new()
frame.Rotation = 0
frame.Parent = nil
crop2:Destroy()
end
crop2, btm = getFramesForBounds(get3DBounds(subj))
frame.Size = UDim2.new(0, scrSize().X, 0, scrSize().Y)
frame.CurrentCamera = workspace.CurrentCamera
crop.Parent = scrGui
crop.Size = UDim2.new(0, cropF.AbsoluteSize.X, 0, cropF.AbsoluteSize.Y)
local pos = workspace.CurrentCamera:WorldToScreenPoint(subj.CFrame.p)
--crop.Position = UDim2.new(0, pos.X-cropF.AbsoluteSize.X/2, 0, pos.Y-cropF.AbsoluteSize.Y/2)
--frame.Position = UDim2.new(0, -crop.AbsolutePosition.X, 0, -crop.AbsolutePosition.Y)
crop2.Parent = crop
frame.Parent = btm
abolutize(frame)
frame.Position = UDim2.new(0, -btm.AbsolutePosition.X, 0, -btm.AbsolutePosition.Y)
--frame.Position = UDim2.new(0, -frame.AbsolutePosition.X, 0, -frame.AbsolutePosition.Y)
end)
I have no idea how to achieve the cropping effect I’d like because of this issue… If anyone has any ideas or knows how I can achieve this effect, please let me know!
Edit 2:
The red box is the area that is incorrect… The green box is the desired area
I essentially want to create four boxes which all cover the green area but my current script gives me the red box.
Edit: ClipsDescendants should work with rotated UI elements - #15 by Tiffblocks