Getting random point on the surface of an ellipsoid

I want to get several points (preferably by a single function that can be ran within a for loop if needed) on the surface of an ellipsoid (scaled part with a sphere special mesh). I have the center since it’s just a part still, and the sizes of the axis as well. I realize that the solution here is going to be really math-heavy and I’m ready for it.

Currently my attempt at it is very rudimentary and guess-y since I have no idea what I’m doing. I think I can create a smaller sphere within it that uses the smallest axis, then get some Gaussian distributions with the mean being the original axis lengths and the smallest, then using a formula I saw on StackExchange (I cannot locate the link now, sorry), and then multiplying my new numbers with the ratios of the original axis and the smallest one. I’m probably going in the complete wrong direction so I don’t really know.

I am using @NoahWillCode 's stats repository for my Gaussian distributions.

(Don’t mind the “big” variable, it was used in an earlier attempt)

Current Code

local stats = require(game.ServerStorage.statistics)

function getpoint()
	local x,y,z = script.Parent.Size.X,script.Parent.Size.Y,script.Parent.Size.Z
	
	local smol = nil
	if x < y and x < z then
		smol = x
	elseif y < x and y < z then
		smol = y
	else
		smol = z
	end
	
	local big = nil
	if x > y and x > z then
		big = x
	elseif y > x and y > z then
		big = y
	else
		big = z
	end
	
	local difX = x/smol
	local difY = y/smol
	local difZ = z/smol
	
	local p1 = stats.distributions.normal(x,smol)
	local p2 = stats.distributions.normal(y,smol)
	local p3 = stats.distributions.normal(z,smol)
	
	local ize = 1/math.sqrt(p1^2+p2^2+p3^2)
	
	local n1,n2,n3 = (p1*ize)*smol,(p2*ize)*smol,(p3*ize)*smol
	
	return Vector3.new(n1*difX, n2*difY, n3*difZ) + script.Parent.Position
end

Any help would be appreciated!

1 Like

If I understood both posts correctly, then I believe this thread explains it well.

Alright, so nearly a month later I decided to check back on this and have come to an answer that’s good enough for my needs, but definitely isn’t perfect. Nonetheless, I’m going to attach it here anyway because it might help somebody else.

This script takes a part (that is using a sphere special mesh), and just gets semi-random points along its surface. I say semi-random because this uses a Gaussian distribution and is definitely biased. I just turned up the distribution’s variance way up to mostly remedy this, but do take that into account. This script is also based on the other scripts mentioned in @hannes213 's reply, but I mostly reached this just by tinkering around with angles/distribution methods for a bit. This code also still uses @NoahWillCode 's stats module script for the distributions.

stats_mod = require(game.ServerStorage.statistics)

function getpoint()
	--gets the axis as radiuses
	local x,y,z = script.Parent.Size.X/2,script.Parent.Size.Y/2,script.Parent.Size.Z/2
	--retrieves the smallest axis
	local smol = nil
	if x < y and x < z then
		smol = x
	elseif y < x and y < z then
		smol = y
	else
		smol = z
	end
	
	--each axis divided by the smallest, one will equal 1
	local difX = x/smol
	local difY = y/smol
	local difZ = z/smol
	--normals / gaussians, done three times seperately for extra randomness
	local p1 = stats_mod.distributions.normal(smol,750)
	local p2 = stats_mod.distributions.normal(smol,750)
	local p3 = stats_mod.distributions.normal(smol,750)
	--this was just through trial and error, i have no idea why this works as well as it does.
	local ize = 1/math.sqrt(p1^2+p2^2+p3^2)
	--also trial and error
	local n1,n2,n3 = (p1*ize)*smol,(p2*ize)*smol,(p3*ize)*smol
	--creates a new position, with the center added to actually place the 'map' onto the ellipsoid
	return Vector3.new(n1*difX, n2*difY, n3*difZ) + script.Parent.Position
end
--just runs through some points, used for testing
for i=1, 20 do
	local pos = getpoint()
		
	local new = Instance.new("Part")
	new.Anchored = true
		
	new.Position = pos
		
	new.CanCollide = false
		
	new.Color = Color3.new(1,0,0)
		
	new.Size = Vector3.new(0.1,0.1,0.1)
		
	new.Parent = workspace
end

Once again, this script is no where near perfect, but it might still help someone with the same problem, who also might be able to make theirs a lot less shoddy than mine.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.