I have found a temporary solution. I have solved this issue by casting 5 rays that each have different offsets to make sure that they don’t miss an area while scanning the model. And you no longer get holes!
Here are some results:
--== SETTINGS ==--
local ModelToPixelate = workspace:WaitForChild("Model") -- The model to pixelate
local ScanningSize = 150 -- The area to scan in all 3 axis
local ScanDistance = 500 -- How far the scanning ray is casted
local KeepMaterials = true -- Use the same materials that the model has
local KeepTransparency = true -- Use the same transparent areas that the model has
local DebugMode = true -- Show the scanning ray's Origin position
--== FUNCTIONS ==--
local BlockCount = 0
local BlockSize = 1
local DebugBrick1
local ModelMover = require(script:WaitForChild("ModelMover"))
local function round(n)
return math.ceil(n - 0.5)
end
local PixelsGroup = Instance.new("Model")
PixelsGroup.Name = "Pixelated " .. ModelToPixelate.Name
PixelsGroup.Parent = ModelToPixelate
function CreateBlock(PartColour, PartMaterial, PartPosition, PartTransparency)
print("Created block" .. BlockCount)
local Block = Instance.new("Part")
Block.Name = "PixelBlock"
Block.Anchored = true
Block.Size = Vector3.new(BlockSize, BlockSize, BlockSize)
Block.TopSurface = Enum.SurfaceType.Smooth
Block.BottomSurface = Enum.SurfaceType.Smooth
Block.Color = PartColour
Block.Position = Vector3.new(round(PartPosition.X), round(PartPosition.Y), round(PartPosition.Z))
if PartMaterial and KeepMaterials then
Block.Material = PartMaterial
else
Block.Material = Enum.Material.SmoothPlastic
end
if PartTransparency and KeepTransparency then
Block.Transparency = PartTransparency
end
Block.Parent = PixelsGroup
BlockCount = BlockCount + 1
return Block
end
function ScanFaceAndPixelate(Origin, Direction)
--print("ORIGIN")
--print(Origin)
--print("DIRECTION")
--print(Direction)
if DebugBrick1 then
DebugBrick1.Position = Origin
end
local Params = RaycastParams.new()
Params.FilterType = Enum.RaycastFilterType.Whitelist
Params.FilterDescendantsInstances = {ModelToPixelate}
local function CastRay(OffsetX, OffsetZ)
local ScanRay = workspace:Raycast(Origin + Vector3.new(OffsetX, 0, OffsetZ), Direction + Vector3.new(OffsetX, 0, OffsetZ), Params)
if ScanRay then
local Hit = ScanRay.Instance
if Hit and Hit:IsA("BasePart") and Hit.Name ~= "PixelBlock" then
--print("RAY HIT POS")
--print(ScanRay.Position)
CreateBlock(Hit.Color, Hit.Material, ScanRay.Position)
end
end
end
CastRay(0, 0)
CastRay(0.25, 0.25)
CastRay(0.5, 0.5)
CastRay(-0.5, -0.5)
CastRay(-0.25, -0.25)
end
--== MAIN ==--
if ModelToPixelate and ModelToPixelate.PrimaryPart then
local OriginalModelToPixelateCFrame = ModelToPixelate:GetPrimaryPartCFrame()
local CurrentPos = Vector3.new(ScanningSize / 2, ScanningSize / 2, ScanningSize / 2)
if DebugMode then
DebugBrick1 = CreateBlock(Color3.fromRGB(255, 0, 0), nil, CurrentPos)
DebugBrick1.Shape = Enum.PartType.Ball
DebugBrick1.Name = "DebugPart"
DebugBrick1.Parent = workspace
DebugBrick1.Transparency = 0.5
DebugBrick1.CanCollide = false
end
-- Begin pixelating the model
function ScanModel()
local CurrentPos = Vector3.new(ScanningSize / 2, ScanningSize / 2, ScanningSize / 2)
for index = 1, ScanningSize do
wait()
for index = 1, ScanningSize do
--print(CurrentPos)
CurrentPos = CurrentPos - Vector3.new(BlockSize, 0, 0)
ScanFaceAndPixelate(CurrentPos, CurrentPos - Vector3.new(0, ScanDistance, 0))
end
CurrentPos = Vector3.new(ScanningSize / 2, ScanningSize / 2, CurrentPos.Z) - Vector3.new(0, 0, BlockSize)
end
end
print("Scanning side 1 out of 6 | Front")
ModelToPixelate:SetPrimaryPartCFrame(CFrame.Angles(0, 0, 0))
--local cframes = ModelMover.GetCFrameTable(ModelToPixelate)
--ModelMover.SetPrimaryPartCFrame(ModelToPixelate, CFrame.Angles(math.rad(0), math.rad(0), math.rad(0)), cframes)
ScanModel()
print("Scanning side 2 out of 6 | Right")
ModelToPixelate:SetPrimaryPartCFrame(CFrame.Angles(math.rad(90), 0, 0))
--cframes = ModelMover.GetCFrameTable(ModelToPixelate)
--ModelMover.SetPrimaryPartCFrame(ModelToPixelate, CFrame.Angles(math.rad(90), math.rad(0), math.rad(0)), cframes)
ScanModel()
print("Scanning side 3 out of 6 | Back")
ModelToPixelate:SetPrimaryPartCFrame(CFrame.Angles(math.rad(180), 0, 0))
--cframes = ModelMover.GetCFrameTable(ModelToPixelate)
--ModelMover.SetPrimaryPartCFrame(ModelToPixelate, CFrame.Angles(math.rad(180), math.rad(0), math.rad(0)), cframes)
ScanModel()
print("Scanning side 4 out of 6 | Left")
ModelToPixelate:SetPrimaryPartCFrame(CFrame.Angles(math.rad(270), 0, 0))
--cframes = ModelMover.GetCFrameTable(ModelToPixelate)
--ModelMover.SetPrimaryPartCFrame(ModelToPixelate, CFrame.Angles(math.rad(270), math.rad(0), math.rad(0)), cframes)
ScanModel()
print("Scanning side 5 out of 6 | Top")
ModelToPixelate:SetPrimaryPartCFrame(CFrame.Angles(0, 0, math.rad(90)))
--cframes = ModelMover.GetCFrameTable(ModelToPixelate)
--ModelMover.SetPrimaryPartCFrame(ModelToPixelate, CFrame.Angles(math.rad(0), math.rad(0), math.rad(90)), cframes)
ScanModel()
print("Scanning side 6 out of 6 | Bottom")
ModelToPixelate:SetPrimaryPartCFrame(CFrame.Angles(0, 0, math.rad(270)))
--cframes = ModelMover.GetCFrameTable(ModelToPixelate)
--ModelMover.SetPrimaryPartCFrame(ModelToPixelate, CFrame.Angles(math.rad(0), math.rad(0), math.rad(270)), cframes)
ScanModel()
--ModelMover.SetPrimaryPartCFrame(ModelToPixelate, OriginalModelToPixelateCFrame, cframes)
ModelToPixelate:SetPrimaryPartCFrame(OriginalModelToPixelateCFrame)
if DebugBrick1 then
DebugBrick1:Destroy()
end
PixelsGroup.Parent = workspace
print(ModelToPixelate.Name .. " has been successfully pixelated! | " .. BlockCount .. " parts created")
else
error("ModelToPixelate is nil or ModelToPixelate has no set PrimaryPart")
end


