I want to optimize my terrain generation with Greedy Meshing (Read about it here Greedy Meshing Voxels)
It worked fine with parts that were 1 stud in volume. But I need custom sizes and I just can’t manage to make it work. I thought that by replacing all the 1 stud increments with the appropiate sizes would work, but the results are nowhere close.
This module uses the Grid module to optimize the parts in the grid
local Greedy = {}
Greedy.__index = Greedy
-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Modules
local Parts = require(ReplicatedStorage.Utility.Parts)
function Greedy.new(grid, partWidth, partHeight)
local self = setmetatable({}, Greedy)
self.grid = grid
self.partWidth = partWidth
self.partHeight = partHeight
return self
end
function Greedy:loop(axis, func)
local xO, yO, zO = self.originPosition.X, self.originPosition.Y, self.originPosition.Z
local xE, yE, zE = self.endPosition.X, self.endPosition.Y, self.endPosition.Z
if axis == "X" then
xO = xO + self.partWidth
elseif axis == "Y" then
yO = yO + self.partHeight
elseif axis == "Z" then
zO = zO + self.partWidth
end
for x = xO, xE, self.partWidth do
for y = yO, yE, self.partHeight do
for z = zO, zE, self.partWidth do
local part = self.grid:get(x, y, z)
local otherPart = nil
if axis == "X" then
otherPart = self.grid:get(x - self.partWidth, y, z)
elseif axis == "Y" then
otherPart = self.grid:get(x, y - self.partHeight, z)
elseif axis == "Z" then
otherPart = self.grid:get(x, y, z - self.partWidth)
end
if not part or not otherPart then continue end
if part:GetAttribute("TerrainType") ~= otherPart:GetAttribute("TerrainType") then continue end
func(x, y, z, part, otherPart)
end
end
end
end
function Greedy:blend(originPosition, endPosition)
if typeof(originPosition) ~= "Vector3" then error("Origin position isn't a Vector3") end
if typeof(endPosition) ~= "Vector3" then error("End position isn't a Vector3") end
-- Parts.new(CFrame.new(originPosition), Vector3.one, "Strong Blue", "Void", workspace)
-- Parts.new(CFrame.new(endPosition), Vector3.one, "Strong Blue", "Void", workspace)
self.originPosition = originPosition
self.endPosition = endPosition
self:loop("Z", function(x, y, z, part, otherPart)
-- Resize part
local newSizeZ = part.Size.Z + self.partWidth
part.Size = Vector3.new(part.Size.X, part.Size.Y, newSizeZ)
-- Remove other part
self.grid:remove(x, y, z - self.partWidth)
end)
self:loop("X", function(x, y, z, part, otherPart)
if part.Size.Z == otherPart.Size.Z then
local newSizeX = part.Size.X + self.partWidth
part.Size = Vector3.new(newSizeX, part.Size.Y, part.Size.Z)
self.grid:remove(x - self.partWidth, y, z)
end
end)
self:loop("Y", function(x, y, z, part, otherPart)
if part.Size.X == otherPart.Size.X and part.Size.Z == otherPart.Size.Z then
local newSizeY = part.Size.Y + self.partHeight
part.Size = Vector3.new(part.Size.X, newSizeY, part.Size.Z)
self.grid:remove(x, y - self.partHeight, z)
end
end)
end
return Greedy
This is the Grid module, it just keeps count of the parts.
local Grid = {}
Grid.__index = Grid
function Grid.new()
local self = setmetatable({}, Grid)
self.data = {};
return self
end
function Grid:get(x,y,z)
if self.data[x] and self.data[x][y] then
return self.data[x][y][z]
end
return nil
end
function Grid:set(x, y, z, part)
if not self.data[x] then
self.data[x] = {
[y] = {}
}
elseif not self.data[x][y] then
self.data[x][y] = {}
end
self.data[x][y][z] = part
end
function Grid:remove(x, y, z)
local entry = self.data[x][y][z]
if entry then entry:Destroy() end
self.data[x][y][z] = nil
end
function Grid:clearY(x, y)
self.data[x][y] = nil
end
function Grid:clearX(x)
self.data[x] = nil
end
function Grid:clearAll()
self.data = {}
end
return Grid
Do I need to rethink the algorithm completlly to handle custom sizes? If i can’t have custom sizes having cubes with sizes bigger than 1 would still suffice, because that doesn’t work either, somehow.