Generating points of a grid inside a rotated shape see if there in bounds chunk culling

  1. What do you want to achieve? Keep it simple and clear!
    i already have a 3d chunk loader (200x200x200 size)
    but for even better performance i want the client to cull away chunks out of frame (behind the player camera thay would be inside of player render distance)

  2. What is the issue? Include screenshots / videos if possible!
    if the render distance is 1 for example would render a cube of chunks around the player where the player is in the center of a 3x3x3 cube grid (rubix cube) and then use WorldRoot:GetPartsInPart()

to see if the chunk is inside or slightly overlapping with the player but this is so inefficient since if u have 10 chunk render distance there is approx 40 chunks that are rendered in and then disapear that should not even render in the first place

i want to get these points (snap to grid) first and then filter the points out that intersect with cube and then render the chunks this would be way faster and better performant since i don’t have to load in chunks and then filter the one that are needed

  1. *What solutions have you tried so far?
    like explained in step 2 i render them in first, but i somehow need to generate a grid of points that intersect with the cube maybe raycasting all the postions but i don’t know if that is performant ?

here is a picture to visualize how i want to cull the chunks and not render them in first but trying to get the position of the chunks that should load in before loading them in to skip over loading in unescesary chunks

if i can generate a X,Z grid but when rotated (points not parts) i can make it different but still pretty performant any ideas how

You can check this post: Check if position is in part - #7 by ThanksRoBama

i made it different more performant this way i removed the culling for now i can still add it to not render in chunks behind the camera (depending on how the camera looks figuring out where is behind the camera even if looking down )

local script inside the character
and a module script with the brain
in case someone else need a simple chunk loader

the chunks are just folder containing all the parts and are named like this
“Col: 400|Row:-200|Index:200”

col = X
row = Z
index = Y

grid size is 200x200x200 im not gonna post my map → chunks converter too much effort

local script:

local humanoid = script.Parent:FindFirstChild("Humanoid") or game.Players.LocalPlayer.CharacterAdded:Wait():WaitForChild("Humanoid")--game.Workspace.CurrentCamera
local hrp = script.Parent:WaitForChild("HumanoidRootPart")
local oldPos = nil
local chunkLib = require(script:WaitForChild("chunk"))
--after spawn
chunkLib.run()
--
--FPS
local fps = 0
local timePos = tick()
spawn(function()
	while game:GetService("RunService").RenderStepped:wait() do
		local difference = math.abs(timePos-tick())
		timePos = tick()
		fps = math.clamp(math.floor(1/difference),0,60)
	end
end)
------
local storedFPSTicks,highestFPS,LowestFPS,averageFPS = {},0,60,0
local chunkRenderDistance = script.chunk.distance
script.chunk.distance.Changed:Connect(function()chunkLib.run()end)
function changeChunkRenderDistance(number)
	chunkRenderDistance.Value = math.clamp(chunkRenderDistance.Value + number,2,20)
end

function fpsCheck(fpsATM)
	if fpsATM > highestFPS then highestFPS = fpsATM end
	if fpsATM < LowestFPS then LowestFPS = fpsATM end
	table.insert(storedFPSTicks,fpsATM)
	print("FPS",fpsATM,"l:",LowestFPS,"h:",highestFPS,"avg:",averageFPS,"(#checks:",#storedFPSTicks..")","R:",script.chunk.distance.Value)
	if #storedFPSTicks > 10 then
		table.remove(storedFPSTicks,1)
	end

	-- calculating average fps from last 10 fpsChecks
	local tempAverageFPS = 0
	for _,storedFps in pairs(storedFPSTicks) do
		tempAverageFPS = tempAverageFPS + storedFps
	end
	math.floor(((tempAverageFPS / #storedFPSTicks)*10)+.5)/10
	averageFPS = tempAverageFPS
	if averageFPS < 50 then changeChunkRenderDistance(-1) return end
	if averageFPS > 59 then changeChunkRenderDistance(1) return end
end

task.spawn(function()
	while wait(2) do
		fpsCheck(fps)
	end
end)

local debounce = false
humanoid.Running:Connect(function(speed)
	while speed > 0 do
		wait(1)
		if debounce then return end
		debounce = true
		if not humanoid or not hrp then return end
		local newPos = chunkLib.positionToGrid(hrp.Position)
		--print("running")
		if newPos ~= oldPos then
			--print("newPos")
			oldPos = newPos
			chunkLib.run()
		end
		debounce = false
	end
end)

module script:

local chunk = {}

local visibleChunks = {}
local busyChunks = {}
local chunkStorage = game:GetService("ReplicatedStorage"):WaitForChild("Chunks")
local chunkRender = game:GetService("Workspace"):WaitForChild("Map"):WaitForChild("Chunks")
local chunkSize = 200--game.Workspace:GetAttribute("ChunkSize")
local renderDistance = script:FindFirstChild("distance")


chunk.positionToGrid = function(PositionInput)
	return Vector3.new(math.floor(PositionInput.X / chunkSize +0.5) * chunkSize, math.floor(PositionInput.Y / chunkSize +0.5) * chunkSize, math.floor(PositionInput.Z / chunkSize +0.5) * chunkSize)
end



chunk.isBusy = function(chunkName)
	if busyChunks[chunkName] then
		--print("busy",chunkName)
		return true -- chunk is busy
	end
	--print("free",chunkName)
	return false -- chunk is free
end

chunk.reserve = function(chunkName)
	--print("reserve",chunkName)
	busyChunks[chunkName] = true -- make a free chunk busy
end

chunk.freeUp = function(chunkName)
	--print("freedUp",chunkName)
	busyChunks[chunkName] = nil -- make a busy chunk free
end

chunk.Load = function(chunkName)
	if visibleChunks[chunkName] or chunk.isBusy(chunkName) then
		return --skip chunk already doing something
	end
	if chunkStorage:FindFirstChild(chunkName) then
		--print("Load chunk")
		chunk.reserve(chunkName)
		chunkStorage:FindFirstChild(chunkName).chunkBoundary.grid.Color3 = Color3.fromRGB(0,255,0)
		chunkStorage:FindFirstChild(chunkName).Parent = chunkRender
		task.wait()
		visibleChunks[chunkName] = true
		chunk.freeUp(chunkName)
	end
end


chunk.Unload = function(chunkName)
	if visibleChunks[chunkName] == nil or chunk.isBusy(chunkName) then
		return --skip chunk already doing something
	end
	if chunkRender:FindFirstChild(chunkName) then
		--print("Unload chunk")
		chunk.reserve(chunkName)
		chunkRender:FindFirstChild(chunkName).chunkBoundary.grid.Color3 = Color3.fromRGB(255,0,0)
		chunkRender:FindFirstChild(chunkName).Parent = chunkStorage
		task.wait()
		visibleChunks[chunkName] = nil
		chunk.freeUp(chunkName)
	end

end


local function renderChunkPoints(centerPosition)
	--print("renderPoints",centerPosition)
	local newlyRendedChunkPoints = {}
	local startX = centerPosition.X - math.floor((renderDistance.Value*chunkSize)+.5)
	local endX = centerPosition.X + math.floor((renderDistance.Value*chunkSize)+.5)
	local startZ = centerPosition.Z - math.floor((renderDistance.Value*chunkSize)+.5)
	local endZ = centerPosition.Z + math.floor((renderDistance.Value*chunkSize)+.5)
	local startY = centerPosition.Y - math.floor((renderDistance.Value*chunkSize)+.5)
	local endY = centerPosition.Y + math.floor((renderDistance.Value*chunkSize)+.5)

	for col = startX,endX,chunkSize do
		for row = startZ,endZ,chunkSize do
			for index = startY,endY,chunkSize do
				if (centerPosition - Vector3.new(col,index,row)).Magnitude <= chunkSize*renderDistance.Value then
					local resolvedChunkName = "Col" .. col .. "|Row" .. row .. "|Index" .. index
					newlyRendedChunkPoints[resolvedChunkName] = true
				end
			end
		end
	end
	return newlyRendedChunkPoints
end


local debounce = false
chunk.run = function()
	if not debounce then
		debounce = true
		if not script.Parent.Parent:WaitForChild("HumanoidRootPart") then return end
		local chunksPoints = renderChunkPoints(chunk.positionToGrid(script.Parent.Parent:WaitForChild("HumanoidRootPart").Position))
		--print("chunkDistance",renderDistance.Value)
		for vChunk,_ in pairs(visibleChunks) do
			if not chunksPoints[vChunk] then chunk.Unload(vChunk) end
		end
		
		for chunkRenderRequest,_ in pairs(chunksPoints) do
			if chunkStorage:FindFirstChild(chunkRenderRequest) then	chunk.Load(chunkRenderRequest)	end
		end
		task.wait(2)
		debounce = false
	end
end

return chunk

the fps counter is to dynamicly change render distance from 2 to 20 chunks around the playerCenter chunk

thx for link i gues its solved

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.