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:
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...
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
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
project the vector onto the cone’s axis
determine if it’s within the height of the cone
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).