How to fill shape inside of GUI?
Asked by
6 years ago Edited 6 years ago
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:
01 | local RunService = game:GetService( "RunService" ) |
04 | local camera = workspace.CurrentCamera |
07 | local vertex = workspace:WaitForChild( "vertex1" ) |
09 | local point = script.Parent |
12 | RunService.RenderStepped:Connect( function () |
14 | local vertPos, vertOnScreen = camera:WorldToScreenPoint(vertex.Position) |
18 | point.BackgroundTransparency = 0 |
20 | point.Size = UDim 2. new( 0 , 10 *( 10 /vertPos.Z), 0 , 10 *( 10 /vertPos.Z)) |
21 | point.Position = UDim 2. new( 0 , vertPos.X - (point.Size.X.Offset / 2 ), 0 , vertPos.Y - (point.Size.Y.Offset / 2 )) |
23 | point.BackgroundTransparency = 1 |
EDGE:
01 | local RunService = game:GetService( "RunService" ) |
04 | local camera = workspace.CurrentCamera |
07 | local vertex 1 = workspace:WaitForChild( "vertex1" ) |
08 | local vertex 2 = workspace:WaitForChild( "vertex2" ) |
11 | local edge = script.Parent |
14 | RunService.RenderStepped:Connect( function () |
16 | local vert 1 Pos, vert 1 OnScreen = camera:WorldToScreenPoint(vertex 1. Position) |
17 | local vert 2 Pos, vert 2 OnScreen = camera:WorldToScreenPoint(vertex 2. Position) |
20 | if vert 1 OnScreen and vert 2 OnScreen then |
21 | edge.BackgroundTransparency = 0 |
24 | local yDelta = vert 2 Pos.Y - vert 1 Pos.Y |
25 | local xDelta = vert 2 Pos.X - vert 1 Pos.X |
28 | edge.Position = UDim 2. new( 0 , (vert 1 Pos.X - (edge.Size.X.Offset / 2 )) + (xDelta / 2 ), 0 , vert 1 Pos.Y - (edge.Size.Y.Offset / 2 ) + (yDelta / 2 )) |
30 | local dist = math.sqrt((xDelta^ 2 )+(yDelta^ 2 )) |
31 | edge.Rotation = math.deg(math.atan(yDelta/xDelta)) |
33 | edge.Size = UDim 2. new( 0 , dist, 0 , 5 *( 5 /vert 1 Pos.Z)) |
35 | edge.BackgroundTransparency = 1 |
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.
01 | local RunService = game:GetService( "RunService" ) |
03 | local camera = workspace.CurrentCamera |
06 | local vertex 1 = workspace:WaitForChild( "vertex1" ) |
07 | local vertex 2 = workspace:WaitForChild( "vertex2" ) |
08 | local vertex 3 = workspace:WaitForChild( "vertex14" ) |
11 | local face = script.Parent |
14 | RunService.RenderStepped:Connect( function () |
16 | local vert 1 Pos, vert 1 OnScreen = camera:WorldToScreenPoint(vertex 1. Position) |
17 | local vert 2 Pos, vert 2 OnScreen = camera:WorldToScreenPoint(vertex 2. Position) |
18 | local vert 3 Pos, vert 3 OnScreen = camera:WorldToScreenPoint(vertex 3. Position) |
20 | local vertPos = { vert 1 Pos, vert 2 Pos, vert 3 Pos } |
23 | if vert 1 OnScreen and vert 2 OnScreen and vert 3 OnScreen then |
24 | face.BackgroundTransparency = 1 |
31 | for _, v in pairs (vertPos) do |
50 | face.Position = UDim 2. new( 0 , minX, 0 , minY) |
53 | face.Size = UDim 2. new( 0 , maxX - minX, 0 , maxY - minY) |
56 | local pixelSize = UDim 2. new( 0 , 5 , 0 , 5 ) |
57 | for i = 0 , face.Size.X.Offset do |
58 | for j = 0 , face.Size.Y.Offset do |
59 | if i % 5 = = 0 and j % 5 = = 0 then |
60 | local pixel = Instance.new( "Frame" , face) |
61 | pixel.Size = pixelSize |
62 | pixel.Position = UDim 2. new( 0 , i, 0 , j) |
64 | pixel.BackgroundColor 3 = Color 3. new( 255 , 255 , 255 ) |
72 | for _, v in pairs (face:GetChildren()) do |
73 | if v:IsA( "Frame" ) then |
78 | face.BackgroundTransparency = 1 |
Actually, now that I think about it, spamming edges would be the most efficient method, as spamming pixels generates more lag.
Thanks, @StreamG0D!