Sorry for bumping, but I came across the same problem and I believe I have found a nice non-matrix solution using lerp.
local function weightedAverageCFrame(weightedCFrames: {{cFrame: CFrame,weight: number}}): CFrame
local average = CFrame.new()
local totalWeight = 0
for _,weightedCFrame in weightedCFrames do
local currentCFrame = weightedCFrame.cFrame
local currentWeight = weightedCFrame.weight
totalWeight += currentWeight
average = average:Lerp(currentCFrame,currentWeight/totalWeight)
end
return average
end
This takes a table of CFrame-weight dictionary pairs, and sequentially lerps the average with each CFrame using increasingly discounted alpha.
How I think it works is that Lerping with alpha currentWeight/totalWeight effectively “multiplies” the average by (1-currentWeight/totalWeight) and adds it with the currentCFrame “multiplied by” currentWeight, as per analogous definitions of lerp in other objects like vectors.
So, in a non-rigorous sense,
average = average*(1-currentWeight/totalWeight) + currentCFrame*(currentWeight/totalWeight)
But
(1-currentWeight/totalWeight)
= (totalWeight/totalWeight-currentWeight/totalWeight)
= (totalWeight-currentWeight)/totalWeight
= previousTotalWeight/totalWeight
Hence
average = average*(previousTotalWeight/totalWeight) + currentCFrame*(currentWeight/totalWeight)
average = (average*previousTotalWeight + currentCFrame*currentWeight)/totalWeight
Thus, we are dividing the weighted sum by the total weight, which gives us the weighted mean. The logic is sound for vectors, so I hope Lerp is sufficiently well defined on CFrames for this to work. In practice, this seems to be the case.
In the case where all weights are equal, this simplifies to
local function averageCFrame(cFrames: {CFrame}): CFrame
local average = CFrame.new()
for i,cFrame in cFrames do
average = average:Lerp(cFrame,1/i)
end
return average
end
This one just takes a table of CFrames.