Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

How to fill shape inside of GUI?

I am creating a cloth simulation, and I have decided that the best method is to create a cage made of Parts and SpringConstraints inside of the Workspace service, then use Camera:WorldToScreenPoint() to generate a wire-frame with edges and vertices inside of the UI. My only problem is being able to generate faces, which require filling in the space in-between edges. So far, the simulation is very realistic, and I do not want to abandon it.

Here is what the simulation looks like so far.

If you want the source code for edges and vertices, here it is. They are all LocalScripts under Frames.

VERTEX:

local RunService = game:GetService("RunService") --RUNSERVICE

--CAMERA
local camera = workspace.CurrentCamera

--PART OF CAGE
local vertex = workspace:WaitForChild("vertex1")

local point = script.Parent --FRAME

--DRAW--
RunService.RenderStepped:Connect(function()
	--FIND WHERE POINT IS ON SCREEN
	local vertPos, vertOnScreen = camera:WorldToScreenPoint(vertex.Position)
	
	--IS THE POINT ON SCREEN?
	if vertOnScreen then
		point.BackgroundTransparency = 0 --VISIBLE
		
		point.Size = UDim2.new(0, 10*(10/vertPos.Z), 0, 10*(10/vertPos.Z)) --SET SCALE BASED ON Z
		point.Position = UDim2.new(0, vertPos.X - (point.Size.X.Offset / 2), 0, vertPos.Y - (point.Size.Y.Offset / 2)) --CENTERED ON POINT IN CAGE
	else
		point.BackgroundTransparency = 1 --INVISIBLE
	end
end)

--BLAHBLAHIDONTKNO

EDGE:

local RunService = game:GetService("RunService") --RUNSERVICE

--CAMERA
local camera = workspace.CurrentCamera

--PARTS OF CAGE
local vertex1 = workspace:WaitForChild("vertex1")
local vertex2 = workspace:WaitForChild("vertex2")

--FRAME
local edge = script.Parent

--DRAW--
RunService.RenderStepped:Connect(function()
	--FIND WHERE POINT IS ON SCREEN
	local vert1Pos, vert1OnScreen = camera:WorldToScreenPoint(vertex1.Position)
	local vert2Pos, vert2OnScreen = camera:WorldToScreenPoint(vertex2.Position)
	
	--CHECK IF POINT IS ON SCREEN
	if vert1OnScreen and vert2OnScreen then
		edge.BackgroundTransparency = 0 --VISIBLE
		
		--DISTANCES FOR X AND Y
		local yDelta = vert2Pos.Y - vert1Pos.Y
		local xDelta = vert2Pos.X - vert1Pos.X
		
		--SET POSITION TO MIDDLE OF TWO POINTS
		edge.Position = UDim2.new(0, (vert1Pos.X - (edge.Size.X.Offset / 2)) + (xDelta / 2), 0, vert1Pos.Y - (edge.Size.Y.Offset / 2) + (yDelta / 2))
		
		local dist = math.sqrt((xDelta^2)+(yDelta^2)) --DISTANCE BETWEEN TWO POINTS
		edge.Rotation = math.deg(math.atan(yDelta/xDelta)) --USE XDELTA AND YDELTA TO COMPUTE ANGLE IN DEGREES
		
		edge.Size = UDim2.new(0, dist, 0, 5*(5/vert1Pos.Z)) --SET LENGTH TO DISTANCE, SET THICKNESS BASED ON Z DIST
	else
		edge.BackgroundTransparency = 1 --INVISIBLE
	end
end)

--BLAHBLAHIDONTKNO

How should I approach filling in the faces?

EDIT: Actually, using knowledge from vector graphics, it could be possible to use the three edges as an "enclosed vector curve", and then create a grid of pixels confined to that group of edges, allowing for custom shapes.

Here is what I am talking about.

So far, I have gotten the grid to track to the triangle by taking the minimum and maximum points, and then positioning and scaling the grid based on those points.

Here's a screenshot.

Here's the current script for the face. I had to modify the size of each "pixel" from 3 pixels to 5 pixels to reduce lag.

local RunService = game:GetService("RunService") --RUNSERVICE

local camera = workspace.CurrentCamera --CAMERA

--PARTS OF CAGE
local vertex1 = workspace:WaitForChild("vertex1")
local vertex2 = workspace:WaitForChild("vertex2")
local vertex3 = workspace:WaitForChild("vertex14")

--CONTAINER OF PIXELS
local face = script.Parent

--DRAW--
RunService.RenderStepped:Connect(function()
	--VERTICES THAT MAKE UP TRI
	local vert1Pos, vert1OnScreen = camera:WorldToScreenPoint(vertex1.Position)
	local vert2Pos, vert2OnScreen = camera:WorldToScreenPoint(vertex2.Position)
	local vert3Pos, vert3OnScreen = camera:WorldToScreenPoint(vertex3.Position)
	
	local vertPos = {vert1Pos, vert2Pos, vert3Pos} --TABLE OF POSITIONS
	
	--DO NOT APPEAR WHEN POINTS ARE OFF SCREEN
	if vert1OnScreen and vert2OnScreen and vert3OnScreen then
		face.BackgroundTransparency = 1 --CONTAINER IS INVISIBLE
		
		--FIND MINIMUM AND MAXIMUM POINTS OF TRI
		local minX = 999999
		local maxX = -999999
		local minY = 999999
		local maxY = -999999
		for _, v in pairs(vertPos) do
			if v.X < minX then
				minX = v.X
			end
			
			if v.X > maxX then
				maxX = v.X
			end
			
			if v.Y < minY then
				minY = v.Y
			end
			
			if v.Y > maxY then
				maxY = v.Y
			end
		end
		
		--DETERMINE POSITION AND SIZE OF GRID BASED ON MIN AND MAX
		face.Position = UDim2.new(0, minX, 0, minY)
		--local dist = math.sqrt((xDelta^2)+(yDelta^2))
		--face.Rotation = math.deg(math.atan(v2Delta/v3Delta))
		face.Size = UDim2.new(0, maxX - minX, 0, maxY - minY)
		
		--DRAW PIXELS
		local pixelSize = UDim2.new(0, 5, 0, 5)
		for i = 0, face.Size.X.Offset do
			for j = 0, face.Size.Y.Offset do
				if i % 5 == 0 and j % 5 == 0 then
					local pixel = Instance.new("Frame", face)
					pixel.Size = pixelSize
					pixel.Position = UDim2.new(0, i, 0, j)
					--pixel.BorderSizePixel = 0
					pixel.BackgroundColor3 = Color3.new(255, 255, 255)
				end
			end
		end
		
		wait()
		
		--REFRESH
		for _, v in pairs(face:GetChildren()) do
			if v:IsA("Frame") then
				v:Destroy()
			end
		end
	else
		face.BackgroundTransparency = 1
	end
end)

--BLAHBLAHIDONTKNO

Actually, now that I think about it, spamming edges would be the most efficient method, as spamming pixels generates more lag. Thanks, @StreamG0D!

5 comments

0

So do you want the faces to be flexible too or are they static within the wire frame?

0

I do want the faces to be flexible, as the whole point of using the UI was to create a deformable mesh based on the cage.

0

The easiest solution I can think of is to use a bunch of edges as a way to fill the grid, but I doubt the engine could handle that.

0

I guess you could place a false CanCollided Part and make it swing with the Cloth, but that'd be exceptionally hard.

0

So I was just looking throug unanswered questions and came across this old one, I am glad you thought my answer was best, but did it actually solve your problem or does it still lag a lot?

1 answer

Yeah so this is a bit of an old question, but I think I have a different answer to all those previously posted.

You can draw 2D triangles if you use image labels and a little bit of math.

You can read this post for the math/code

And for the image labels I recommend checking out Quenty's post as opposed to the images I uploaded as they'll get rid of the black line issue that mine have.

Hope this helps!

This discussion is preserved as it was. New answers, comments, and votes are closed.