Fixing lidar dots using math.floor

I’m making a lidar system right now but I’m running into the issue where dots will be placed on top of dots, despite their CanQuery being false, and them supposedly meant to be checking if anything occupies the grid


I assume the best way would be by checking the distances maybe but I don’t want to cause any unnecessary lag that is already currently being caused

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

-- Objects
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Camera = workspace.CurrentCamera

local MapBlocks = workspace:WaitForChild("MapBlocks")
local WorldDots = workspace:WaitForChild("Dots")
local DotReserve = WorldDots:WaitForChild("DotReserve")

-- Storage
local ScanAction = ReplicatedStorage.InputContexts.Gameplay.Scan
local TemplateDot = script:WaitForChild("Dot")

-- Modules
local SharedModules = ReplicatedStorage.Modules.Shared
local PartCache = require(SharedModules:WaitForChild("PartCache"))

-- Caches
local DotCache = PartCache.new(TemplateDot, 1500, DotReserve)
local DotGrid = {}

-- Values
local LastScan = os.clock()

local Step = 10 / (25 - 1)
local Offset = -10 / 2
local MaxRaycast = 50

local ScanParams = RaycastParams.new()
ScanParams.FilterType = Enum.RaycastFilterType.Exclude

ScanAction.Pressed:Connect(function()
	if (os.clock() - LastScan) > 1 then
		LastScan = os.clock()
		
		local CameraPivot = Camera:GetPivot()
		local Direction = CameraPivot.LookVector * 45
		local RaycastCount = 0
		
		local ScanTable = {Character}
		for _, v in CollectionService:GetTagged("ScanDot") do table.insert(ScanTable, v) end
		ScanParams.FilterDescendantsInstances = ScanTable
		
		for X = 0, 25 - 1 do
			for Y = 0, 25 - 1 do
				local XOffset = Offset + (X * Step)
				local YOffset = Offset + (Y * Step)
				local Origin = CameraPivot.Position + CameraPivot.RightVector * XOffset + CameraPivot.UpVector * YOffset
				
				local Cast = workspace:Raycast(Origin, Direction, ScanParams)
				if Cast then
					local CastPosition = Cast.Position
					local GridPosition = Vector3.new(math.floor(CastPosition.X), math.floor(CastPosition.Y),  math.floor(CastPosition.Z))
					
					if not DotGrid[GridPosition] then
						local NewDot = DotCache:GetPart()
						NewDot.Position = GridPosition
						
						DotGrid[GridPosition] = NewDot
					end
				end
				
				RaycastCount += 1
				if RaycastCount >= MaxRaycast then
					RaycastCount = 0
					RunService.Heartbeat:Wait()
				end
			end
		end
	end
end)
5 Likes


I tried your script, idk i cant replicate the error. I wrote my own partcache but overall it works just fine.

1 Like

you probably wanted to say “CanCollide”.

if you aren’t going to be helpful please don’t respond. canquery is a boolean on parts you can disable which makes them get ignored by raycasts that don’t have respectcancollide

5 Likes

my setup does happen to have L shaped walls so I believe that could possibly be why? I don’t think the part cache would do anything but I’m interested in what you did anyway

I still need assistance with this as it’s still happening

here's the script i used (it's updated version of yours)
--!strict

const DeleteDelay = 1

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

-- Objects
local Player = assert(Players.LocalPlayer)
local Character = Player.Character or Player.CharacterAdded:Wait()
local Camera = assert(workspace.CurrentCamera)

-- Storage
local ScanAction = ReplicatedStorage.InputContexts.Gameplay.Scan

-- Caches
local DotGrid = {}

-- Values
local LastScan = os.clock()

local Step = 10 / (25 - 1)
local Offset = -10 / 2
local MaxRaycast = 50

local ScanParams = RaycastParams.new()
ScanParams.FilterType = Enum.RaycastFilterType.Exclude

local index = 0

local function createDot(position: Vector3, color: Color3)
	local NewDot = Instance.new("Part")
	NewDot.Name = "dot_" .. tostring(index)
	NewDot.Transparency = .25
	NewDot.Size = Vector3.one * .5
	NewDot.Anchored = true
	NewDot.CanQuery = false
	NewDot.CanCollide = false
	NewDot.Position = position
	NewDot.Material = Enum.Material.Neon
	NewDot.Color = color
	NewDot.Parent = workspace.Dots
	
	index += 1
	
	return NewDot
end

ScanAction.Pressed:Connect(function()
	print("ScanAction.Pressed")
	if (os.clock() - LastScan) > 1 then
		LastScan = os.clock()

		local CameraPivot = Camera:GetPivot()
		local Direction = CameraPivot.LookVector * 45
		local RaycastCount = 0
		
		ScanParams.FilterDescendantsInstances = {Character}

		for X = 0, 25 - 1 do
			for Y = 0, 25 - 1 do
				local XOffset = Offset + (X * Step)
				local YOffset = Offset + (Y * Step)
				local Origin = CameraPivot.Position + CameraPivot.RightVector * XOffset + CameraPivot.UpVector * YOffset

				local Cast = workspace:Raycast(Origin, Direction, ScanParams)
				if Cast then
					local CastPosition = Cast.Position
					local GridPosition = Vector3.new(math.floor(CastPosition.X), math.floor(CastPosition.Y),  math.floor(CastPosition.Z))

					if not DotGrid[GridPosition] then
						local NewDot = createDot(GridPosition, Color3.new(0, 1, 0))
						Debris:AddItem(NewDot, DeleteDelay)
						
						NewDot.AncestryChanged:Once(function(child: Instance, parent: Instance)
							assert(not parent)
							createDot(NewDot.Position, Color3.new(1, 1, 0))
						end)

						DotGrid[GridPosition] = NewDot
					end
				end

				RaycastCount += 1
				if RaycastCount >= MaxRaycast then
					RaycastCount = 0
					RunService.Heartbeat:Wait()
				end
			end
		end
	end
end)

workspace.Dots.ChildAdded:Connect(function(child: Instance)
	print("child", child)
end)

Here’s the video:

  • dots do not overlap: pressing Scan without moving camera does not add dots to occupied positions

the problem is definitely not in math.floor(CastPosition.X), math.floor(CastPosition.Y), math.floor(CastPosition.Z)

you can test that Vector3 == operator works correctly easily with:

local t = {}
t[Vector3.new()] = true
t[Vector3.new()] = true
print(t)
  • two different Vector3 instances have been put into the table
  • table size == 1 because their value is the same

The problem is somewhere else. Please check your code.

What’s likely happening in your case is that dot at

DotGrid[GridPosition]

actually does not have its .Position == GridPosition

If your walls are Meshes and L shaped it could be that the Box Collision Fidility is to course and raycast hits it + math.floor so they float, try PerciseConvexDecomposition (if that is the case). And my partcache just creates parts that have no CanQuery and CanCollide set to false and it creates them 10000 times or so and if it exceeds the cached, it creates new ones and places them at the position.

1 Like

they aren’t meshes just normal parts, and my parts have the same properties as yours, so I’m very confused

1 Like

I’ve checked and it does seem to as they all accurately follow a grid, and it’s not all the time dots are placed on top of dots

how do you know this happens?..
i mean these are similar parts, how do you recognize that one is in the same place as another?

because in my post I have a screenshot of it literally happening and I’m trying to fix that. what I said was unrelated to your code srry

could you please post the screenshot again with circles around overlapped dots?
could you please provide experience file with just models that you scan to achieve overlapped dots, so we can check the meshes also?
thank you!

they are not overlapping, just put on top of each other


lidar.rbxl (74.2 KB)

could you please clarify that?
what does “on top of each other” mean for you? they occupy same place in 3d space? or they appear at the same place on screen?

they are physically on top of each other and offset via the grid, please look at the screenshot and test the game, I do not think I can explain it any better

i have tested, and @vm_core as well, and we have not found cases when dots occupy same place.
that’s why i am asking

could you please provide a screenshot pointing which dots are “on top of each other”?
what i am expecting is, for example:

  • dots in pink circle are “on top of each other” (they are not actually, but that’s what for examples are)

thank you!


flipping the image probably makes it make more sense

excuse me, but that’s a one dot.

are you rage baiting me or can you really not flip in image in your head like I said to see what I mean by on top

I’m not going to circle around 20 dots just fill in the gaps bro