Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/snippets/feature.6906.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- (#6906) Tweak the formula used to calculate the level of detail (LOD) for props.
51 changes: 29 additions & 22 deletions lua/system/blueprints-props.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,31 +107,38 @@ end
--- - https://github.com/FAForever/fa/pull/4675
---@param prop PropBlueprint
local function ProcessLOD(prop)

local sx = prop.SizeX or 1
local sy = prop.SizeY or 1
local sz = prop.SizeZ or 1

-- give more emphasis to the x / z value as that is easier to see in the average camera angle
local weighted = 0.40 * sx + 0.2 * sy + 0.4 * sz
if prop.ScriptClass == 'Tree' or prop.ScriptClass == 'TreeGroup' then
weighted = 10.0
end

-- https://www.desmos.com/calculator (0.9 * sqrt(100 * 500 * x))
local lod = 0.9 * MathSqrt(100 * 500 * weighted)

if prop.Display and prop.Display.Mesh and prop.Display.Mesh.LODs then
local n = TableGetn(prop.Display.Mesh.LODs)
for k = 1, n do
local data = prop.Display.Mesh.LODs[k]

-- https://www.desmos.com/calculator (x * x)
local factor = (k / n) * (k / n)
local LODCutoff = factor * lod
local sx = prop.SizeX or 1
local sy = prop.SizeY or 1
local sz = prop.SizeZ or 1

-- give more emphasis to the x / z value as that is easier to see in the average camera angle
local weightedLodSize = MathSqrt(sx * sx + 0.5 * sy * sy + sz * sz)
local maxLod = 180 * weightedLodSize

if (prop.ScriptClass == 'Tree' and TableGetn(prop.Display.Mesh.LODs) == 3) then
prop.Display.Mesh.LODs[1].LODCutoff = 40
prop.Display.Mesh.LODs[2].LODCutoff = 200
prop.Display.Mesh.LODs[3].LODCutoff = 640
return
elseif (prop.ScriptClass == 'TreeGroup' and TableGetn(prop.Display.Mesh.LODs) == 3) then
Copy link
Member

@Garanas Garanas Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of elseif after a return statement is confusing. It gives the impression that the function can continue. The return will already make you exit the function.

It's better to just write:

if (...) then

   (...)

   return
end

if (...) then

   (...)

   return
end

-- default case when no special rules apply

(...)

prop.Display.Mesh.LODs[1].LODCutoff = 200
prop.Display.Mesh.LODs[2].LODCutoff = 200
prop.Display.Mesh.LODs[3].LODCutoff = 640
return
elseif (prop.ScriptClass == 'Tree' or prop.ScriptClass == 'TreeGroup') then
maxLod = 640
end

local levels = TableGetn(prop.Display.Mesh.LODs)
for n = 1, levels do
local data = prop.Display.Mesh.LODs[n]
local factor = (n / levels)
local LODCutoff = factor * maxLod

-- sanitize the value
data.LODCutoff = MathFloor(LODCutoff / 10 + 1) * 10
-- round the value
data.LODCutoff = MathFloor((LODCutoff + 5) / 10) * 10
end
end
end
Expand Down
Loading