 # Using Math to generate Cylinders?

1. What do you want to achieve?
I want to be able to generate hollow Cylinders using math.

2. What is the issue?
I do not know the math used to generate Cylinders. I only know the math for a circle and Sphere.

3. What solutions have you tried so far?
I have tried asking in various discords. Looked on Google and Dev forum.

Circle Generation.

``````local Radius = 1
local Circle = math.pi * 2
local Amt = 10000

for Number = 1, Amt do
local Angle = Circle / Amt * Number
local X = math.sin(Angle) * Radius
local Z = math.cos(Angle) * Radius
end
``````

Sphere Generation

``````local function fibonacci_spiral_sphere(num_points)
local vectors = {}
local gr = (math.sqrt(5) + 1) / 2
local ga = (2 - gr) * (2 * math.pi)

for i = 1, num_points do
local lat = math.asin(-1 + 2 * i / (num_points + 1))
local lon = ga * i

local x = math.cos(lon) * math.cos(lat)
local y = math.sin(lon) * math.cos(lat)
local z = math.sin(lat)

table.insert(vectors, Vector3.new(x, y, z))
end

return vectors
end
``````

If anyone could help that would be nice (I’m trying to create a game like no man’s sky).

It’s the same math as generating a circle except you increment the Y position. If it makes sense, cylinders are basically infinitely stacked circles. Just like how a sphere is infinitely many circles, but instead they’re different sizes.

``````local Radius = 1
local Circle = math.pi * 2
local Amt = 10000
local Height = 10

for Y = 0, Height do
for Number = 1, Amt do
local Angle = Circle / Amt * Number
local X = math.sin(Angle) * Radius
local Z = math.cos(Angle) * Radius

local Position = Vector3.new(X, Y, Z)
end
end
``````

If you’re confusing on what I meant by “infinitely many stacked circles” try reading these. You don’t really need to understand the math, but they explain the concept with nice graphics:

2 Likes

Why don’t you just use `Instance.new`? I don’t think there will be much of a difference.

Following content might be considered rude

Very hard math to generate a cylinder.

``````--hard code to generate clyinder
local thing = Instance.new("Part")
thing.Shape = Enum.PartType.Cylinder
``````

Maybe he wants a cylinder that is procedurally generated.

`Cylinder` is not an Instance type. Your code will error. However, it is a PartType.

``````local Cylinder = Instance.new("Part")

Cylinder.Shape = Enum.PartType.Cylinder``````
2 Likes

I noticed you have made a couple of posts about shapes, so I feel the need to ask, what is your use case for this? Do you need to just render the surfaces of a cylinder? Or do you have to be able to compute every possible point inside the cylinder? If so then you would have to integrate through the length and radius as @SwagMasterAndrew pointed out.

1 Like

No, No, No I want a hollow cylinder generated by many many parts like the sphere code I want that only a cylinder shape

I need it for a infinite game im making using -perlin noise and custom structurs.,

1 Like

This is sorta off topic but I am trying to get into generating different shapes as well so I have some questions:

``````local Radius = 1
local Circle = math.pi * 2
local Amt = 10000
local Height = 10

for Y = 0, Height do
for Number = 1, Amt do
local Angle = Circle / Amt * Number
local X = math.sin(Angle) * Radius
local Z = math.cos(Angle) * Radius

local Position = Vector3.new(X, Y, Z)
end
end
``````

How does multiplying pi by 2 make a circle (in your circle variable)?

Why do you use sin and cos, how does it work?

Also what is it mean if something is procedurally generated?

Thanks!

math.pi * 2 makes sure th circle is a full circle so math.pi * 1 would be a semi - circle etc

But pi is just a number, 3,14… How can that be a semi-circle?

because we are diving math.pi by Amt

You already have a function to generate a sphere. To generate cylinder with this method, all you have to do is to achieve a constant radius. Remove `cosine` factors from the coordinates calculations.

Cylinder Generation:

``````local function spiral_cylinder(num_points)
local vectors = {}
local gr = (math.sqrt(5) + 1) / 2
local ga = (2 - gr) * (2 * math.pi)

for i = 1, num_points do
local lat = math.asin(-1 + 2 * i / (num_points + 1))
local lon = ga * i

local x = math.cos(lon) --remove * math.cos(lat)
local y = math.sin(lon) --remove * math.cos(lat)
local z = math.sin(lat)

table.insert(vectors, Vector3.new(x, y, z))
end

return vectors
end
``````

Hope this helps!

This does not make a Cylinder?

``````local function spiral_cylinder(num_points)
local vectors = {}
local gr = (math.sqrt(5) + 1) / 2
local ga = (2 - gr) * (2 * math.pi)

for i = 1, num_points do
local lat = math.asin(-1 + 2 * i / (num_points + 1))
local lon = ga * i

local x = math.cos(lon) --remove * math.cos(lat)
local y = math.sin(lon) --remove * math.cos(lat)
local z = math.sin(lat)

table.insert(vectors, Vector3.new(x, y, z))
end

return vectors
end

for Number, Vector3 in pairs(spiral_cylinder(1000)) do
local Part = Instance.new("Part")
Part.Anchored = true
Part.Parent = workspace
end
``````

I am not sure what Vector3.Unit is supposed to do, it sure behaves strange. However this works:

``````for Number, v in pairs(spiral_cylinder(1000)) do
local Part = Instance.new("Part")
Part.Anchored = true
Part.Parent = workspace
end
``````

How would I change the length?

You will need to add another parameter for length. Due to way this function works, it will be still dependent on both this and radius though.

``````local function spiral_cylinder(num_points,length)
local vectors = {}
local gr = (math.sqrt(5) + 1) / 2
local ga = (2 - gr) * (2 * math.pi)

for i = 1, num_points do
local lat = math.asin(-1 + 2 * i / (num_points + 1))
local lon = ga * i

local x = math.cos(lon)
local y = math.sin(lon)
local z = math.sin(lat) * length

table.insert(vectors, Vector3.new(x, y, z))
end

return vectors
end
``````

Usage:

``````for Number, v in pairs(spiral_cylinder(1000,10)) do
local Part = Instance.new("Part")
Part.Anchored = true
Part.Parent = workspace
end
``````

Do you know how to generate a cuboid?

Here’s a sample I just typed up:

(I used the size and position of a brick named “Box” for the parameters)

``````local function hollow_cuboid(length, width, height, centerPosition, resolution)
-- 'centerPosition' can be either a Vector3 or a CFrame
-- (orientation will default to {0, 0, 0} if a Vector3 is used)
local pos = (typeof(centerPosition) == "CFrame") and centerPosition
or (typeof(centerPosition) == "Vector3") and CFrame.new(centerPosition)
or CFrame.new()
local vectors = {}
local hl = length / 2
local hw = width / 2
local hh = height / 2
local rr = 1 / resolution -- 'resolution' is points per stud, 'rr' is number of studs between points

-- bottom + top (length * width)
-- left + right (length * height)
for i = -hl, hl, rr do
for j = -hw, hw, rr do
table.insert(vectors, (pos * CFrame.new(j, -hh, i)).Position)
table.insert(vectors, (pos * CFrame.new(j, hh, i)).Position)
end
for j = -hh, hh, rr do
table.insert(vectors, (pos * CFrame.new(-hw, j, i)).Position)
table.insert(vectors, (pos * CFrame.new(hw, j, i)).Position)
end
end
-- front + back (width * height)
for i = -hw, hw, rr do
for j = -hh, hh, rr do
table.insert(vectors, (pos * CFrame.new(i, j, -hl)).Position)
table.insert(vectors, (pos * CFrame.new(i, j, hl)).Position)
end
end
return vectors
end

local box = workspace.Box.Size
local vs = hollow_cuboid(box.Z, box.X, box.Y, workspace.Box.CFrame, 1)

for _, v in ipairs(vs) do
local p = Instance.new("Part")
p.Size = Vector3.new(0.2, 0.2, 0.2)
p.Anchored = true
p.CFrame = CFrame.new(v)
p.Parent = workspace
--wait()
end
``````

Result:

WOW! Thanks so much. This will help in my game a lot! btw, In my other thread didn’t you say you had a triangle generator?

It didn’t make triangle prisms like the rectangle script, it just draws a triangle between three vector3 vertices. I originally made it to render the surface of the sphere I mentioned in the last thread.

``````local function make_triangle(a, b, c, thickness)
-- sanitize input
a = (typeof(a) == "Vector3") and a or Vector3.new(0, 0, 0)
b = (typeof(b) == "Vector3") and b or Vector3.new(1, 0, 0)
c = (typeof(c) == "Vector3") and c or Vector3.new(0, 1, 0)
thickness = math.max((tonumber(thickness) or 1), 0.05)

-- re-order vertices so that AB is the longest side
local a0, b0, c0 = a, b, c
local ab = (a - b).Magnitude
local bc = (b - c).Magnitude
local ca = (a - c).Magnitude
if (bc > ab) then
-- ab not the longest side
if (ca > bc) then
-- ca longest
a = c0
b = a0
c = b0
else
-- bc longest
a = b0
b = c0
c = a0
end
else
-- ab longer than bc
if (ca > ab) then
-- ca longest
a = c0
b = a0
c = b0
else
-- ab longest
end
end
ab = (a - b).Magnitude
bc = (b - c).Magnitude
ca = (a - c).Magnitude

local area = (b - a):Cross(c - a).Magnitude / 2
local h = 2 * area / ab
local hx = math.sqrt((ca ^ 2) - (h ^ 2))

-- cframe stuff
local f = (b - a).Unit
local u = (c - a).Unit
local r = f:Cross(u).Unit
local u2 = r:Cross(f).Unit
local cf = CFrame.fromMatrix(a, r, u2)

-- parts
local p1 = Instance.new("WedgePart")
p1.Anchored = true
p1.Size = Vector3.new(thickness, h, hx)
p1.CFrame = cf * CFrame.new(0, h / 2, -(hx / 2)) * CFrame.Angles(0, math.pi, 0)
p1.Parent = workspace
local p2 = Instance.new("WedgePart")
p2.Anchored = true
p2.Size = Vector3.new(thickness, h, ab - hx)
p2.CFrame = cf * CFrame.new(0, h / 2, -(ab + hx) / 2)
p2.Parent = workspace

return p1, p2 -- so the user can do more stuff with it
end
``````