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:

https://math.libretexts.org/Bookshelves/Calculus/Book%3A_Active_Calculus_(Boelkins_et_al)/6%3A_Using_Definite_Integrals/6.2%3A_Using_Definite_Integrals_to_Find_Volume
https://www.mathalino.com/reviewer/derivation-formulas/derivation-formula-volume-sphere-integration

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.
image

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

local Radius = 100

for Number, Vector3 in pairs(spiral_cylinder(1000)) do
	local Part = Instance.new("Part")
	Part.Anchored = true
	Part.CFrame = CFrame.new(Vector3.Unit * Radius)
	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.CFrame = CFrame.new(v * Radius)
	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.CFrame = CFrame.new(v * Radius)
	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