How I can get angle between vector and mesh's face? (Or directional vector of mesh's face)

So, after some deeper research and tries to understand what’s wrong, I understood what I did wrong and what you was telling me:
image
So, in some cases, droplet can be too close to wall with my old check so it will detect only blocking wall, ignoring lower one. (Previous check checked base velocity and velocity + gravity. So it was worst method I had ever tbh, bc limit of this was 2 walls)
So, I rescripted detection method a bit:

local Droplet = Droplets[i]
local StartVelocity = Droplet.Velocity
SurfaceParams.FilterDescendantsInstances = Droplets
local Normals = {}
local function TestVelocity(Start, Velocity)
	local VelocityGrav = Velocity - Vector3.new(0, Gravity * CurDelay, 0) 
	local Offset = VelocityGrav.Unit / 20
	local RayStart = -Offset + Start
	local RayDirection = VelocityGrav + Offset
	local Result = workspace:Raycast(RayStart, RayDirection, SurfaceParams)
	local RaycastDistanceTarget = (VelocityGrav.Magnitude + Offset.Magnitude) * CurDelay + 0.05
	local ResultSucceed = Result and Result.Distance <= RaycastDistanceTarget and 2 or Result and 1 or 0
	local Distance = math.huge
	if ResultSucceed == 2 then
		if #Normals > 100 then
			error("TOO MANY NORMALS")
		else
			local found = false
			for i = 1, #Normals, 1 do
				if Normals[i]:FuzzyEq(Result.Normal, 0.001) then
					found = true
					break
				end
			end
			if not found then
				table.insert(Normals, Result.Normal)
				local Normal = Normals[1]
				for i = 2, #Normals, 1 do
					Normal += Normals[i]
				end
				Distance = Result.Distance
				Normal = Normal.Unit
				local NextVelocity = Velocity - Velocity:Dot(Normal) * Normal
				local PreDistance = TestVelocity(Start, NextVelocity)
				Distance = PreDistance ~= math.huge and PreDistance or Distance
			end
		end
	end
	return Distance
end

local Distance = TestVelocity(Droplet.Position, StartVelocity)
local Velocity = StartVelocity - Vector3.new(0, Gravity * CurDelay, 0)
local PossibleMovement = Velocity * CurDelay
local Normal = Normals[1]
if #Normals > 0 then
	for i = 2, #Normals, 1 do
		Normal += Normals[i]
	end
	Normal = Normal.Unit
	local NewVelocity = (Velocity - Velocity:Dot(Normal) * Normal)-- * Friction
	local DistanceProportion = math.min(Distance / NewVelocity.Magnitude, 1) * 0.99
	Velocity = (Velocity * (0.99 - DistanceProportion) + NewVelocity * (0.01 + DistanceProportion)) * Friction
	PossibleMovement = Velocity * CurDelay
	Velocity = NewVelocity * Friction
end

And also I found small bug which goes in action when you detect surface. So, there’s previous and reflection velocities. If surface detected, 100% power will go to reflect velocity. On big speeds this can result in hitting mid-air. And I tried to fix this one too. But failed - again due to clipping problems.

I’m pretty sure decreasing offset (by, for example, diving by 30 instead of 20) will fix that, it’ll decrease distance needed for raycast to count as raycast so making this mid-air movements be less noticeable.

I already had 1/100. Result is ± same. I think that problem may come from Distance / Velocity.Magnitude, but I’m not sure.

Pretty weird, can you explain why you add to CurDelay every frame? That increases the distance too.

Sorry for long wait time, tried to fix code, unsucceed again.
If you asking about why I do this:

CurDelay += Delta
if Debounce == false  then
	Debounce = true

Then, you can find later this:

CurDelay = 0
Debounce = false

So, I do so, to keep approximate droplet velocities if they start to lag, and single update cycle don’t fits one heartbeat interval. At the end, after this cycle finishes, I reset value… And only now I realized that this won’t change anything, because it will reset added value and droplets will still act as usual framerate * lag… Another bug found =]

Edit:
Fixed that (so it will stack now if there’s lags)

RunService.Heartbeat:Connect(function(Delta)
	IncDelay += Delta
	if Debounce == false and IncDelay > WaitAmount then
		CurDelay = IncDelay - WaitAmount
		IncDelay = 0
		CurDelay = 1/60 -- big values won't cause clipping, while small ones will
		Debounce = true
		local i = 1
		local EndValue = #Droplets
		while i <= EndValue do
			...
		end
		Debounce = false
	end
end

So, now it should stack time, and at diffirent framerates, result will be approximatelly the same.

Does the old problem still exist? If so, can you show a video of it happening? Maybe I’ll understand more.

I can either record video, or give you test file. I’ll record video for around 30-60 minutes due to my potato pc. (I send you studio file for now, also, some code comments can be outdated)