How would I make a tree generator?

Also how would I use ray.Magnitude? Isn’t magnitude a measurement for distance?

yes, i think there was a way to establish a ray’s lenght, and if it touched nothing it would return where the ray would end based on lenght provided. so then you use (origin - hitPosition).Magnitude to get the effective distance between the start and end.

Firstly, why rays? You can just use CFrames.

Im not very good with CFrames how would I do what you suggested?

If you get the relative CFrame of a branch then you can multiply it with half the Y axis size which will get you the tip of the branch then you can create another branch there. Also, you can use CFrame.Angles if you want to rotate the new branch.

alright, thank you for the explanation

Rays are used to check collisions. idk why you need it in this case

you just need to generate a random direction in a 3d cone relative to the previous generated direction.

local rng_v = Random.new()

function RandomVectorOffset(v, maxAngle) --returns uniformly-distributed random unit vector no more than maxAngle radians away from v
    return (CFrame.new(Vector3.new(), v)*CFrame.Angles(0, 0, rng_v:NextNumber(0, 2*math.pi))*CFrame.Angles(math.acos(rng_v:NextNumber(math.cos(maxAngle), 1)), 0, 0)).LookVector
end

The function by

you’ll start by getting the first direction from the up vector of the base

local max_angle = math.pi/8
local FirstDirection = RandomVectorOffset(BasePart.CFrame.UpVector, angle)

and then

local SecondDirection = RandomVectorOffset(FirstDirection, angle)

and keep going like that in a loop getting random directions that are limited by the angle you setted up and building the tree trunk

would this allow for a branch off of another branch or just building branches on a trunk

yes for sure
if you want 2 branchs
make 2 directions out of the previous direction instead of 1 direction


I actually just learnt this by researching your problem in a more mathematical way

I’m having troubles understanding, these are just angles right?

It’s not easy btw. basically I gave you just the key to the problem you’re facing
which is generating a random direction in a 3D cone.
I might implement it in my free time
I’ll make sure to share it with you and the community if it is successful

ah alright I’m just very confused as to how you build off of the angles

1 Like

You can use the angles with CFrame.Angles. But remember it’s in radians.

I faced the same problem when I was younger. but I didn’t had enough math and cframe background to do it.
Now you reminded me of the problem I had. I guess right now I figured out the solution theoretically lol

Here I achieved one branching


this is the code that I used:

local PartTemplate = Instance.new("Part")
PartTemplate.Anchored = true

local function Line(a, b, parent)
	local new = PartTemplate:Clone()
	new.Size = Vector3.new(1,1, (a-b).magnitude)
	new.CFrame = CFrame.new((a+b)/2, b)
	new.Parent = parent
	
	return b, new.CFrame.LookVector
end

local vec = Vector3.new
local v = {
	ZERO = vec(0,0,0),
	UP = vec(0,1,0)
}

local branchHeight = 5
local maxAngle = math.pi/4
local last, lastVec = Line(v.ZERO, v.UP*branchHeight, workspace)
local PartPerBranch = 10

local rng_v = Random.new()

function RandomVectorOffset(v, maxAngle) --returns uniformly-distributed random unit vector no more than maxAngle radians away from v
	return (CFrame.new(Vector3.new(), v)*CFrame.Angles(0, 0, rng_v:NextNumber(0, 2*math.pi))*CFrame.Angles(math.acos(rng_v:NextNumber(math.cos(maxAngle), 1)), 0, 0)).LookVector
end

for i=0, PartPerBranch, 1 do
	last, lastVec = Line(last, last+RandomVectorOffset(lastVec, maxAngle)*branchHeight, workspace)
end

hm, how would you split the branches though?

1 Like

That’s what am going to try now

local PartTemplate = Instance.new("Part")
PartTemplate.Anchored = true

local function Line(a, b, parent)
	local new = PartTemplate:Clone()
	new.Size = Vector3.new(1,1, (a-b).magnitude)
	new.CFrame = CFrame.new((a+b)/2, b)
	new.Parent = parent
	
	return b, new.CFrame.LookVector
end

local vec = Vector3.new
local v = {
	ZERO = vec(0,0,0),
	UP = vec(0,1,0)
}

local branchHeight = 5
local maxAngle = math.pi/8
local last, lastVec = Line(v.ZERO, v.UP*branchHeight, workspace)
local PartPerBranch = 1000

local rng_v = Random.new()

function RandomVectorOffset(v, maxAngle) --returns uniformly-distributed random unit vector no more than maxAngle radians away from v
	return (CFrame.new(Vector3.new(), v)*CFrame.Angles(0, 0, rng_v:NextNumber(0, 2*math.pi))*CFrame.Angles(math.acos(rng_v:NextNumber(math.cos(maxAngle), 1)), 0, 0)).LookVector
end

for i=0, PartPerBranch, 1 do
	last, lastVec = Line(last, last+RandomVectorOffset(lastVec, maxAngle)*branchHeight, workspace)
	local branch = math.random(0,1) == 0
	if branch then
		local last, lastVec = Line(last, last+RandomVectorOffset(lastVec, math.pi/2)*branchHeight, workspace)
		for i=0, 3, 1 do
			last, lastVec = Line(last, last+RandomVectorOffset(lastVec, maxAngle)*branchHeight, workspace)
		end
	end
end

I found the pattern. now I just need to generalize it into a function


This is the most beautiful thing I have ever made through a devforum question xD

5 Likes