There’s no explanation of what the epsilon argument is for Vector3::isClose and all the mentions of it on the forum use it without an explanation. What does it mean and how do I use it?
The epsilon argument specifies the radius, isClose is used to check if another Vector3 is within the radius of the first Vector3.
i.e
local vec1 = Vector3.new()
local vec2 = Vector3.new(0,10,0)
print(vec1:isClose(vec2,5)) -- false
print(vec1:isClose(vec2,10)) -- true
edit: i was wrong about this
This is not how :isClose works iirc. It doesn’t check the radius, but instead the distance on each axis. The behavior also differs if the first vector isn’t (0, 0, 0).
Not sure why this behavior hasn’t been documented.
Some examples:
thisVector:isClose(partPosition) was true for green parts and false for red parts. The center text shows current thisVector values.
Repro code
local thisVector = Vector3.new(1,0,0)
local function createPart(pos, text)
local part = Instance.new("Part")
part.Anchored = true
part.CanCollide = false
part.Size = Vector3.new(.5,.5,.5)
part.TopSurface = "Smooth"
part.BottomSurface = "Smooth"
part.CFrame = CFrame.new(pos)
part.Parent = workspace
if(text)then
local billboardGUI = Instance.new("BillboardGui",part)
billboardGUI.Size = UDim2.new(0,100,0,50)
billboardGUI.AlwaysOnTop = true
billboardGUI.ExtentsOffset = Vector3.new(0,1,0)
local textLabel = Instance.new("TextLabel",billboardGUI)
textLabel.Text = text
textLabel.Size = UDim2.new(1,0,1,0)
textLabel.BackgroundTransparency = 1
textLabel.TextStrokeTransparency = 0
textLabel.TextColor3 = Color3.new(1,1,1)
textLabel.TextSize = 18
end
return part
end
createPart(thisVector, tostring(thisVector)).BrickColor = BrickColor.Black()
for i = 1, 100 do
local otherVector = thisVector + Vector3.new(math.random(-10,10), 0, math.random(-10,10))
createPart(otherVector).BrickColor = (thisVector:isClose(otherVector,5) and BrickColor.Green() or BrickColor.Red())
end
local edgeVec = thisVector + Vector3.new(10, 0, 10)
createPart(edgeVec, tostring(edgeVec)).BrickColor = (thisVector:isClose(edgeVec,5) and BrickColor.Green() or BrickColor.Red())
workspace.CurrentCamera.CameraType = "Scriptable"
workspace.CurrentCamera.CFrame = CFrame.new(0,20,0)*CFrame.Angles(-math.pi*0.5,0,0)
isClose (or the undocumented PascalCase alias Vector3::FuzzyEq) essentially subtracts the two vectors from one another and compares the resulting vector’s magnitude to epsilon
. It’s to make it possible to perform comparisons on Vector3s, which use floats and thus run into floating point issues when comparing them.
Epsilon’s default value is something like 0.000001 iirc.
It seems like you described exactly what Halalaluyafail3 said which Coeptus said was wrong. Are you saying it’s specifically to check if two vectors are very close in order to avoid floating point errors?
Yes. It’s essentially a, well, fuzzy equality operation (thus the name of the alias). You can use it with larger epsilon values like how Coeptus was saying, but that’s not the intended use.
Was looking into this out of curiosity and expanded on Coeptus’ code to help me visualize what kind of inclusion occurred when using this. Helped me understand what was happening better so I thought I would share it.
Feel free to change/add vectors/epsilon values to test yourself.
Code
--[[modification of Coeptus' code]]--
local testVectors = {
Vector3.new(0,1,0),
Vector3.new(1,1,0),
Vector3.new(2,2,0),
Vector3.new(7,7,0)
}
local testEpsilons = {0, 0.5, 1, 1.5, 2, 3}
local testTime = 2 --seconds delay before running next test
local origin = Vector3.new(0,0,0)
local size = 10
game.Lighting.ClockTime = 12
game.Lighting.GlobalShadows = false
local sky = Instance.new("Sky")
sky.Parent = game.Lighting
sky.CelestialBodiesShown = false
local gui = game:GetService("StarterGui")
local screen = Instance.new("ScreenGui")
screen.Parent=gui
local list = Instance.new("UIListLayout")
list.Parent = screen
local vectorLabel = Instance.new("TextLabel")
vectorLabel.TextSize=20
vectorLabel.Size = UDim2.new(0.2,0,0.1,0)
vectorLabel.Parent = screen
local epsilonLabel = Instance.new("TextLabel")
epsilonLabel.Size = vectorLabel.Size
epsilonLabel.TextSize=20
epsilonLabel.Parent = screen
--holds the bricks
local bricks = {}
--makes a brick
local function createPart(pos)
local part = Instance.new("Part")
part.Transparency = .95
part.Anchored = true
part.CanCollide = false
part.Size = Vector3.new(.8,.8,.8)
part.TopSurface = "Smooth"
part.BottomSurface = "Smooth"
part.CFrame = CFrame.new(pos)
part.Parent = workspace
return part
end
--makes bricks
local function generate()
size = 2*size+1
for u = 1, size do
for i = 1, size do
for o = 1, size do
bricks[((u-1)*size*size)+((i-1)*size)+(o)] = createPart(
Vector3.new(o-(math.floor(size/2))-1,u-(math.floor(size/2))-1,i-(math.floor(size/2))-1))
end
end
wait()
end
end
local function runTest()
for v in pairs(testVectors) do
local vector = testVectors[v]
vectorLabel.Text = ("Vector: ("..vector.X..","..vector.Y..","..vector.Z..")")
for e in pairs(testEpsilons) do
local epsilon = testEpsilons[e]
epsilonLabel.Text = ("Epsilon: "..epsilon)
for i in pairs(bricks) do
local pos = bricks[i].Position
if pos == origin then
bricks[i].Transparency = 0
bricks[i].BrickColor = BrickColor.Green()
else
bricks[i].Transparency = (vector:isClose(pos, epsilon) and .05 or 0.95)
end
if i%200 ==1 then
wait()
end
end
wait(testTime)
end
end
end
generate()
while true do
runTest()
end
green part is your origin (0,0,0)
blocks rendered visible are ‘close’