How would I limit a vector projection given the following?

Hello,
I’ve been experimenting with conic projections and ran into something that I wanted to accomplish which is to prevent (clamp) a vector from falling inside of a cone…

I was able to get my orthogonal vector from the original cone axis, but after that im not quite sure on how to calculate the vector needed to get this clamped vector value.
The image below vaguely explains the visual proposition:
affa307b-51cb-4408-b9c5-c677a03962ae

The red line represents the axis vector, the direction in which the cone should be facing, whilst the purple line indicates the input direction (taken from a point, and cone origin point)

The green “fixed” vector is what I’m trying to accomplish; where if the vector lies within the angle/depths of the cone, then it should clamp along the surface of the cone vector, and not INSIDE of it.

These are my calculated values.

local point = Vector3.new()
local pos = point + Vector3.new(0,-1,1).Unit

	local direction = point - pos
	local distance = (pos.Y - point.Y)
	distance = math.max(min_length, distance) -- height
	
	local distance2 = radius/2 -- the base radius
	local distance3 = math.sin(distance/distance2)
	local orthogonal = direction.Unit - (axis*direction.Unit:Dot(axis));
	
	local cf = CFrame.new(Vector3.new(), axis) + pos -- the axis cframe
	local cf2 = CFrame.new(Vector3.new(), orthogonal) + pos -- the orthogonal cframe
--not sure where to take it from here using these values...

Thank you for the read!

Hello,

You’ll want to find out which position on the cone’s axis the vector’s position in the cone corresponds to. I have written code below. The part that natively concerns you is the function “isPointInCone” and its return values. I have also attached a picture below of what it does to the “checkPart” blue piece when placed inside the cone.

local cone = {
	base = 6;
	height = 15;
	origin = Vector3.new(0,10,0);
	direction = Vector3.new(1,0,0);
}

local function renderCone(c)
	local lines = 10
	local p = Instance.new("Part")
	p.Anchored = true
	p.Size = Vector3.new(0.1,0.1,c.height)
	p.BrickColor = BrickColor.Yellow()
	
	local endPoint = CFrame.new(c.origin + (c.direction*c.height))
	for i = 1, lines do
		local pc = p:Clone()
		local angle = (2 * math.pi / lines) * (i -1)
		local lookBack = CFrame.lookAt(endPoint.Position, c.origin)
		local rotation = lookBack * CFrame.Angles(0,0,angle)
		local lineEnd = rotation * CFrame.new(0,c.base/2,0)
		pc.CFrame = CFrame.lookAt(c.origin, lineEnd.Position) * CFrame.new(0,0,-c.height/2)
		pc.Parent = workspace
	end
end

local function isPointInCone(v3, c)
	local distInsideCone = (v3-c.origin):Dot(c.direction)
	
	if (distInsideCone < 0 or distInsideCone > c.height) then
		return false
	end
	
	local radiusAtConeDistance = (distInsideCone / c.height) * c.base/2
	local orthDistance = ((v3-c.origin) - (c.direction * distInsideCone)).magnitude
	local positionOnConeAxis = (c.origin + (c.direction * distInsideCone))
	return orthDistance < c.base/2, radiusAtConeDistance, positionOnConeAxis, (v3 - positionOnConeAxis).unit
end

renderCone(cone)

while wait(1.5) do
	local checkPart = workspace.checkPart
	local isInCone, radiusAtPoint, positionOnConeAxis, directionToSurface = isPointInCone(checkPart.Position, cone)
	if (isInCone) then
		print("Clamping")
		checkPart.Position = positionOnConeAxis + directionToSurface * radiusAtPoint
	else
		print("Outside!")
	end
end

Clamping this piece (or vector [the position]) to the cone’s surface.

It works with cones at any direction, any angle, etc.

image
image

7 Likes

You’re amazing my guy, thank you for the supreme assist! It’s exactly what I was looking to do. Do you have any reference you used to compute this? If so, do you mind linking me to that?

Not really. It’s sort of just knowing that a cone is a set of circles on a linear equation with varying radii.

You

  1. project the vector onto the cone’s axis
  2. determine if it’s within the height of the cone
  3. Fetch the radius of the circle (percentage along the cone’s axis out of the radius)

That’ll tell you if it’s in the cone. To translate it to a point on the surface, just get the direction from the projected point on the cone’s axis to the original vector/point you’re checking against. Then multiply that distance by the radius of the cone (at that given point).

(point - pointOnConeAxis).unit * radiusOfConeAtPoint

1 Like