#How to implement LOD (Level Of Detail)

1 messages · Page 1 of 1 (latest)

livid dawn
#

I am currently working on a voxel game like minecraft, and I’d like to implement a level of detail system that allows me to render chunks distant to the player with less resolution in order to improve performance. While I understand the basic concepts of LOD and octrees, I have no idea how to actually implement them for this use case. I’ve looked through github and dev forums to no avail. My main questions are: how would you determine what block type should be placed in each position of a lower resolution chunk, and how would you know which chunks need to have their resolution updated when the player moves? I’d appreciate any related resources too

turbid galleon
#

Like the greater radii has a lower LOD since it's further out but the lower radii have higher LOD because they're closer

#

I think doing it from the characters hrp position would be enough to justify the LOD radii

#

Now for implementation, just do it when the player's position updates. However, depending on how many instances are loaded, you may want to prioritize by doing closer instances first then further instances later

#

you can use stuff like remotes depending on how ur stuff is set up

#

I'm working on something similar and plan to add LOD so if I did get this wrong someone please do correct me

iron totem
#

just use whats best for your datastructure
for example, i used octrees
and i just store color data for every node, not just leaf nodes, so i can just stop going further down the octree
other option would be, if youre using noise, just reduce the sample points
if storing every block (like a 3d texture)
you could calculate the average, or just use one corner
whatever fits best for your use case

livid dawn
shut jettyBOT
#

studio** You are now Level 1! **studio

livid dawn
#

I don’t think that’d be very good because then you’d still technically need to store or atleast sample through the “lower levels” of the tree even for huge LODs that represent like thousands of blocks with only one

iron totem
#

you could do something like that
or just one sample point per voxel as you should look more in to performance in roblox
depends how noisy your noise is cat
small details like a one block sized flower could get 4/8 blocks big on a lower LOD

#

i think most people kinda try to avoid LODs a bit and more focus on other optimizations
like GreedyMeshing / Culling / better chunk loading
those can make a big difference without really visual impact

livid dawn
iron totem
#

yea thats kinda the issue

#

on the other hand, LODs are normally so far away that you shoudnt see that much of those small mistakes it does

livid dawn
#

Hmmm fair

#

How did you make your octree system?

iron totem
#

i didnt do it in roblox hmm

livid dawn
livid dawn
turbid galleon
iron totem
#

thats also the part i have issues with, my chunk loading is completely broken evilcat

livid dawn
turbid galleon
#

streaming enabled is good for stuff like that that takes up absurd amounts of ram

#

afaik

iron totem
#

yea but thats more like for pre generated stuff
not voxel terrain agony

livid dawn
#

So about octrees, I imagine you’d first get the largest parent node the player is in representing the lowest resolution (like a LOD4 representing 16^3 16^3 chunks with just 1 voxel per chunk) and then subdivide it, find which of the child nodes the player is in, subdivide that, then repeat until you get to LOD0 (16^3 chunk)

#

But actually you’d need to subdivide the surrounding LOD1s too? Because if you do it the way I described the LOD1 chunks would be way too close to the player, but then you’d have to subdivide everything else too… I don’t know

shut jettyBOT
#

studio** You are now Level 2! **studio

livid dawn
#

chat am I cooking

local nids = Enum.NormalId:GetEnumItems()
local Resolutions = {[0] = 16, 8, 4, 2, 1}

local function CreateNode(X,Y,Z,LOD)
local Resolution = Resolutions[LOD]
local NodePart = Instance.new("Part")
NodePart.Position = vector.create(X+Resolution/2, Y+Resolution/2, Z+Resolution/2)
NodePart.Size = vector.one * Resolution
NodePart.Anchored = true
NodePart.CanCollide = false
NodePart.Transparency = 1
NodePart.Parent = workspace
for _, n in nids do
local Outline = Instance.new("Decal")
Outline.Face = n
Outline.Texture = "rbxassetid://"..84335509
Outline.Parent = NodePart
end
return {X=X,Y=Y,Z=Z,LOD=LOD,Part=NodePart}
end

local function SubdivideNode(Node)
local X, Y, Z = Node.X, Node.Y, Node.Z
local ChildLOD = Node.LOD + 1
local Resolution = Resolutions[ChildLOD]
Node.Children = {
[0] = CreateNode(X, Y, Z, ChildLOD), -- -X, -Y, -Z
CreateNode(X + Resolution, Y, Z, ChildLOD), -- +X, -Y, -Z
CreateNode(X, Y + Resolution, Z, ChildLOD), -- -X, +Y, -Z
CreateNode(X + Resolution, Y + Resolution, Z, ChildLOD), -- +X, +Y, -Z
CreateNode(X, Y, Z + Resolution, ChildLOD), -- -X, -Y, +Z
CreateNode(X + Resolution, Y, Z + Resolution, ChildLOD), -- +X, -Y, +Z
CreateNode(X, Y + Resolution, Z + Resolution, ChildLOD), -- -X, +Y, +Z
CreateNode(X + Resolution, Y + Resolution, Z + Resolution, ChildLOD), -- +X, +Y, +Z
}
Node.Part:Destroy()
Node.Part = nil
end

#

local function ContainsPosition(Node, Position)
local X, Y, Z = Position.X, Position.Y, Position.Z
local Resolution = Resolutions[Node.LOD]
return X>=Node.X and X<=Node.X+Resolution and Y>=Node.Y and Y<= Node.Y+Resolution and Z>=Node.Z and Z<=Node.Z+Resolution
end

local Node = CreateNode(0, 0, 0, 0)
local PlayerPosition = vector.create(3, 6, 9)
if ContainsPosition(Node, PlayerPosition) then
while Node.LOD ~= 4 do
SubdivideNode(Node)
for _, ChildNode in Node.Children do
if ContainsPosition(ChildNode, PlayerPosition) then
Node = ChildNode
end
end
end
end