Obtaining the normal/orientation of a surface of a stretched sphere

So I am trying to make a sphere-like object where the spherical coordinates are calculated into a 3D cartesian coordinate. There are already existing formula for this.
image

Problem however is that this assumes a unit sphere, where the normal is it’s position in cartesian space. This becomes a problem if you scale the object non-uniformally. As result you need to adjust the orientation of the points to account for the scaling. As seen here

image

This is what I have. Simply select a part and it will make a stretched sphere once run

local get = game:GetService("Selection"):Get()[1]

local circle = Instance.new("Part")
circle.Material = Enum.Material.Metal
circle.Color = Color3.new(218/255, 133/255, 65/255)
circle.Shape = Enum.PartType.Cylinder
circle.Size = Vector3.new(.2,3,3)
--circle.Transparency = .5
local Rad = 10
local holder = Instance.new("Model")
holder.Parent = workspace

local origin = CFrame.new(get.Position)

for lat = 10, 190, 10 do
	for lon = 0, 360, 20 do
		local clat = math.rad(lat)
		local clon = math.rad(lon+((lat/20)%2)*10)
		local cf = origin
			*CFrame.new(
				Rad*math.sin(clat)*math.sin(clon),
				2*Rad*math.cos(clat),
				Rad*math.sin(clat)*math.cos(clon))
			*CFrame.fromEulerAnglesYXZ(clat, clon, 0)
			*CFrame.Angles(0,math.pi/2,math.pi/2)
		local cc = circle:Clone()
		cc.CFrame = cf
		cc.Parent = holder
		wait()
	end
end
1 Like

image

local holder = Instance.new("Model")
holder.Parent = workspace

local circle = Instance.new("Part")
circle.Material = Enum.Material.Metal
circle.Color = Color3.fromRGB(218, 133, 65)
circle.Shape = Enum.PartType.Cylinder
circle.Size = Vector3.new(.2,3,3)
circle.CanCollide = false
circle.Anchored = true

--circle.Transparency = .5
local a, b, c = 10, 20, 10

local function getEllipsoidPos(lat, lon)
	local clat = math.rad(lat)
	local clon = math.rad(lon+((lat/20)%2)*10)
	
	return Vector3.new(
		a * math.sin(clat) * math.sin(clon),
		b * math.cos(clat),
		c * math.sin(clat) * math.cos(clon))
end

local function getEllipsoidNormal(point)
	return 2 * Vector3.new(point.X / (a^2), point.Y / (b^2), point.Z / (c^2))
end

for lat = 10, 190, 10 do
	for lon = 0, 360, 20 do
		local point = getEllipsoidPos(lat, lon)
		local normal = getEllipsoidNormal(point)
		
		local cf = CFrame.new(point, point + normal) * CFrame.Angles(0,math.rad(90),0)
		local cc = circle:Clone()
		cc.CFrame = cf
		cc.Parent = holder
		task.wait()
	end
end
2 Likes