Rotating a group of points based on a pivot point BUT the rotation has to be a vector direction

local pivot = SequencePoints[1]

for i,v in pairs(T) do
    	local newpivot = CFrame.new(pivot)
    	local offset  =  newpivot:toObjectSpace(v.CFrame)
    	newpivot = newpivot * CFrame.Angles(0, math.rad(10), 0)
    	v.CFrame = newpivot * offset -- Re-offset the part from the new rotation
    end

Right now I’m using this cool formula (above) I found in devforum. The problem with this is it rotates based on angles.

But I want it to pivot to a vector3 direction. use case? Im allowing players to make custom bullet paths, when they shoot I need to rotate the sequence points they made with there path in the direction of the gun barrel using GunBarrel.Front.CFrame.LookVector

Here’s what I mean by ‘rotating’ sequence points if you don’t have any clue what I’m saying.
https://gyazo.com/02c38ab74f87984fd236046beda11fd0
https://gyazo.com/9b1483c0f0182f13a66cc41449006aeb

(Watch the second one)

Try this function.

local function rotate(pivotTargetDir, originalPoints, pointParts)
	local pivot = originalPoints[1]
	local pivotRotationCf = CFrame.new(pivot, pivot+pivotTargetDir)
	for i = 2, #originalPoints do
		local originalPoint = originalPoints[i]
		local posOffset = originalPoint-pivot
		posOffset = Vector3.new(posOffset.X, posOffset.Y, -posOffset.Z)
		local newPoint = pivotRotationCf*posOffset
		pointParts[i].Position = newPoint
	end
end

Here’s some code I used to test it on a baseplate.

local Players = game:getService("Players")
local RunService = game:GetService("RunService")

local startPositions = {
	Vector3.new(7, 0, 5),
	Vector3.new(4, 0, 10),
	Vector3.new(7, 0, 12),
	Vector3.new(13, 0, 16),
	Vector3.new(8, 0, 21)
}

local plr = Players.LocalPlayer
local mouse = plr:GetMouse()

local pointParts = {}

local pointPartFolder = Instance.new("Folder")
pointPartFolder.Parent = workspace

local function createPointPart(num, pos, parent)
	local part = Instance.new("Part")
	part.Name = "P"..num
	part.Color = Color3.new(1, 1, 1)
	part.Material = Enum.Material.SmoothPlastic
	part.Shape = Enum.PartType.Ball
	part.Anchored = true
	part.Size = Vector3.new(1, 1, 1)
	part.Position = pos
	part.Parent = parent
	return part
end

local function createPointParts(positions, parent)
	for i, v in ipairs(positions) do
		pointParts[i] = createPointPart(i, v, parent)
	end
end

createPointParts(startPositions, pointPartFolder)

local pivot = startPositions[1]
RunService.RenderStepped:Connect(function()
	rotate(mouse.Hit.Position-pivot, startPositions, pointParts)
end)
1 Like

https://gyazo.com/bbc5a3c6fa6f3244c37495e5290ae5a2

can you guess what this is? is it welding, oh no it isn’t it’s custom welding, using pivot poin vector rotations lol.

This will be very useful for my path making system. Thank you so much! Would you mind if you could explain a bit of the math, this part:

for i = 1, #originalPoints do
		local originalPoint = originalPoints[i]
		local posOffset = originalPoint-pivot
		posOffset = Vector3.new(posOffset.X, posOffset.Y, -posOffset.Z)
		local newPoint = pivotRotationCf*posOffset
		pointParts[i].Position = newPoint
	end

Also I realised that I didn’t actually need to pivot around the first sequence point of the path, and instead pivot around the root, without your visual example I wouldn’t have realized this so thanks for that to. So now I pivot around the Root instead of the first sequence of the path.

Well, here’s some math explanation. posOffset is the offset in worldspace (relative to origin CFrame) between the pivot and another point. The calculations always use the same point coordinates to calculate the offset, instead of using the positions of the point parts. This means that the offsets used in the calculations are always the same.

The new calculated point, which is then set as the position of a point part, has to be offsetted based on a spesific direction. This can be achieved by CFrame calculations.

The functions creates a CFrame (pivotRotationCf) which’s LookVector points in the direction given to the function. Then it uses the offset that was calculated earlier to calculate the new point so that its offset relative to the new CFrame is the same as the offset of the corresponding original point relative to the origin CFrame. This calculation is done by multiplying the new CFrame with the offset, because multiplying a CFrame with a Vector3 gives a world space position that, when turned into object space of the CFrame, would be equal to the Vector3 in the multiplication. (The position of the original point relative to origin CFrame would be the same as the result of the calculation below, however, there is no reason to multiply the origin CFrame with a Vector, because you’ll just get that same Vector. But maybe this can help understand why I calculate the new point by multiplying the new CFrame with the offset.)

-- the result of this calculation is equal to posOffset
CFrame.new()*posOffset

-- the result of this calculation is equal to posOffset too.
CFrame.new():PointToObjectSpace(CFrame.new()*posOffset)

-- and so is the result of this
pivotRotationCf:PointToObjectSpace(pivotRotationCf*posOffset)

The reason why posOffset’s Z is turned into its opposite is because the negative Z direction is the forward direction of a CFrame. This isn’t really necessary to do in the function as the correct direction could be properly calculated outside the function instead.

Hopefully this explanation makes sense :sweat_smile:.

1 Like