# Which is faster? :GetPartBoundsInRadius() or Magnitude checking?

I am coding an interactive grass system for grass to move arround when a player walks into it, I am trying to optimize it as much as I can.

One of the optimizations involves checking how far all of the grass is from the camera, this is so it stops being simulated and grass very far away is destroyed or replaced with imposters.

In order to check this I determined that most efficient methods are using :GetPartsBoundsInRadius() without overlap params to be faster, and comparing the distance of all existing grass against the cameraâ€™s position using .Magnitude.

The issue is that I donâ€™t know which one is faster, all I know is that technically the more items we need to loop through and check magnitude, the slower it will get, but I also donâ€™t know how slower :GetPartBoundsInRadius() will be compared to.

3 Likes

I have widely seen Magnitude used over anything else. But honestly its more opinion than anything.

3 Likes

They are fundamentally different, so it doesnâ€™t make sense to compare them. `:GetPartBoundsInRadius()` checks if the partâ€™s bounding box is touching the imaginary sphere defined by the radius. But a magnitude check will only consider the center point of the part, i.e. its position.

4 Likes

Yeah they are different, but you can accomplish the same thing with both if you know how to. I think more so it is a usecase and most people just use magnitudeâ€¦

1 Like

Magnitude is definitely faster because itâ€™s only dealing with math. Using GetPartBoundsInRadius is a spatial query operation that does a lot of 3D stuff with special rules like OverlapParams, so itâ€™s slower.

Also, you get the benefit of native codegen and algebra trickery for using only math (you can avoid using squareroots which is usually slow to calculate)

``````if pos:Dot(pos) <= radius^2 then
--is the same as
--but avoids using squareroots
``````
1 Like

I am aware they both work diferently, but keep in mind performing individual checks inside lua, can actually end up being slower than a single function that runs internally, its the reason why bulkMoveTo() can be more efficient.

Also It does makes sense to compare them because internally I doubt :GetPartBoundsInRadius() is grabbing every single bounding boxâ€™s vertices and then comparing them, or something like that, so it could end up being faster than magnitude.

2 Likes

I am unsure if thats faster due to magnitude getting an update a long time ago.

[PSA] .Magnitude Now Obliterates Squared Distance Checks in Luau (With benchmarks!) - Development Discussion - Developer Forum | Roblox

1 Like

You seem to have dodged what I said about native codegen. You can mark your function to be compiled to assembly and have it run faster than any C API. Also, a function that runs internally can still be running tons of loops that you just canâ€™t see.

If you think about it, thatâ€™s the only way for it to determine if a box is inside a radius. It needs to check the vertices to see if theyâ€™re within range.

That post is quite a while ago and the Luau language has evolved dramatically since. Hereâ€™s my test results as of today:

If youâ€™re still not convinced, you can run the same exact code they provided for the benchmark:

And about the native codegen I mentioned: all of them gets faster. Iâ€™m using the new native attribute.

3 Likes

wait wait, can you benchmark :GetPartBoundsInRadius() i am just curious as to the difference in performance now.

Also is there a way to get the distance value using the square root, or nah?

2 Likes

Nuh if you want to get the magnitude you actuallyâ€¦ have to get the magnitude. Which means using Pythagorean theorem which involves squareroots. You can only avoid squareroots if youâ€™re just comparing distances.

You can definitely test it yourself but if it means convincing you then

``````@native local function partsInRadius(parts: {BasePart}, r: number): {BasePart}
local t: {BasePart} = {}
local r2: number = r^2

for _, p in parts do
local pos: Vector3 = p.Position
if pos:Dot(pos) <= r2 then
table.insert(t, p)
end
end

return t
end

local parts: {BasePart} = workspace.Folder:GetChildren()
local start: number = os.clock()