I’m working on a voxel game, and I’m having trouble getting decent performance on my block selection code. I have an invisible part in CurrentCamera with a SelectionBox in it that I CFrame every RenderStep to the appropriate position if the player’s mouse has a target, and if the position isn’t the same as it was the previous frame. I thought that binding this to RenderStep was the problem, but changing it to an event that updates less frequently, like Mouse.Move, yields similar results. The FPS drop is only visible when the selected block changes, but it persists for a second or so after that. Using the Rendering panel (shift + F2), I saw that, when switching positions, the CPU timing goes up dramatically (from about ~12ms to ~32ms). For some context, the system functions in this way because my terrain is greedy meshed. In other words, simply switching the SelectionBox’s adornee isn’t an option. The part is anchored, CanCollide false, doesn’t cast a shadow, and is completely transparent. Commenting out the CFrame change eliminates any performance issues, but that’s obviously not a solution. Not really sure what I can do to solve this. Here’s the code:
RunService.RenderStepped:connect(function()
local targetSurface = mouse.TargetSurface
if targetSurface then
local mouseHit = mouse.Hit
local normal = normals[targetSurface]
local currentBlock = Vector3.new(math.floor((mouseHit.x - normal.X) / 3) * 3 + 1.5, math.floor((mouseHit.y - normal.Y) / 3) * 3 + 1.5, math.floor((mouseHit.z - normal.Z) / 3) * 3 + 1.5)
if currentBlock ~= previousBlock then
selectionPart.CFrame = CFrame.new(currentBlock)
selection.Visible = true
previousBlock = currentBlock
end
elseif previousBlock ~= nil then
selection.Visible = false
previousBlock = nil
end
end)
I reverse engineered the rest of your code (because I’ve done this before) and I’m getting 0 performance drops. Nothing from the code indicates that I should either. Are you sure it’s this script? Here’s my code
local RunService = game:GetService("RunService")
local selectionPart = Instance.new("Part")
selectionPart.Anchored = true
selectionPart.CanCollide = false
selectionPart.Parent = workspace
selectionPart.Size = Vector3.new(3, 3, 3)
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
Mouse.TargetFilter = selectionPart
local previousBlock = nil
local normals = {
[Enum.NormalId.Back] = Vector3.new(0, 0, 1),
[Enum.NormalId.Bottom] = Vector3.new(0, -1, 0),
[Enum.NormalId.Front] = Vector3.new(0, 0, -1),
[Enum.NormalId.Left] = Vector3.new(-1, 0, 0),
[Enum.NormalId.Right] = Vector3.new(1, 0, 0),
[Enum.NormalId.Top] = Vector3.new(0, 1, 0)
}
RunService.RenderStepped:connect(function()
local targetSurface = Mouse.TargetSurface
if targetSurface then
local mouseHit = Mouse.Hit
local normal = normals[targetSurface]
local currentBlock = Vector3.new(math.floor((mouseHit.x - normal.X) / 3) * 3 + 1.5, math.floor((mouseHit.y - normal.Y) / 3) * 3 + 1.5, math.floor((mouseHit.z - normal.Z) / 3) * 3 + 1.5)
if currentBlock ~= previousBlock then
selectionPart.CFrame = CFrame.new(currentBlock)
selectionPart.Transparency = 0
previousBlock = currentBlock
end
elseif previousBlock ~= nil then
selectionPart.Transparency = 1
previousBlock = nil
end
end)
Yeah, I’m confident. I tried commenting out the CFrame line, and something about that seems to tank performance. A few things I noticed:
If Roblox Studio’s window isn’t in focus, the performance problems aren’t as extreme. No FPS drops, but CPU timing does still go up a decent amount.
Performance is alright on my laptop with a pretty fast processor. On a slower (but still reasonably average) computer with an i3-7100u, performance drops from about 60 FPS to ~40 FPS.
If I delete a block (which requires me to rerun my greedy meshing algorithm, reparent/resize 40+ parts, and change their CFrames using BulkMoveTo), changing the selection part’s CFrame, there are virtually no performance drops. However, simply moving my mouse to move the selection part does. Very strange.
Also, nice job reverse engineering my code, I had to double check to see if I posted the entire snippet.
Setting a single CFrame won’t tank performance, and your specs are fine. By itself, the code works fine. My only guess is that something is trying to interact with that part and causing it to bork. Are you doing any Region3s or GetTouchingParts()?
EDIT: Is your greedy mesher trying to remesh every frame when your mouse hovers? Idk how your system works but it’s a guess.
No Region3s or GetTouchingParts(), and I triple-checked to make sure that the greedy mesher only ran when needed. I suspect that this might be rendering or physics-related. When I simply move the mouse around to change the selection part’s CFrame, the performance issues appear. When I do the exact same thing and click (to delete a block, running the greedy meshing code), no performance issues. It’s very strange.
I’ve attached a baseplate with the code. CPU timing goes from about 13ms when there’s no mouse movement to 26ms when moving the mouse around quickly (on my slower PC). blockselector.rbxl (21.5 KB)
This is truly bizarre. CFraming the part every frame causes my FPS to drop from ~250 to ~200. And it’s not even your script. Just CFraming any part every frame is having the same effect.
I used the microprofiler to track how long the function is taking to run, and it’s very quick. What’s changing is the Rendering task apparently. Even if the part isn’t parented to workspace, it still affects the Render task. I honestly have no idea what’s going on.
Can you try binding the function to RunService.Heartbeat? Kind of curious to see if there’s any performance differences between RenderStepped and Heartbeat.
What’s really strange is that I’m not even changing the CFrame every frame. It’s only when the block that’s supposed to be selected changes that this happens. A single update to the CFrame is causing this drop, which makes absolutely no sense to me.
At this point I’m completely stumped. Is changing a CFrame just supposed to be that intensive of a task? Simply changing the SelectionBox’s adornee won’t work for the reason mentioned in the original post. I don’t know what else to do other than change the CFrame of a block. If SelectionBox had an offset that would work, but obviously that’s not the case. Not sure what to do.