Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
8

How to fill shape inside of GUI?

Asked by
y3_th 176
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:

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!

0
So do you want the faces to be flexible too or are they static within the wire frame? SteamG00B 1633 — 6y
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. y3_th 176 — 6y
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. SteamG00B 1633 — 6y
0
I guess you could place a false CanCollided Part and make it swing with the Cloth, but that'd be exceptionally hard. TheOnlySmarts 233 — 6y
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? SteamG00B 1633 — 5y

1 answer

Log in to vote
0
Answered by
EgoMoose 802 Moderation Voter
5 years ago
Edited 5 years ago

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!

Ad

Answer this question