Recently I have been wanting to allow the player to rotate models inside a viewport frame as I am making a crafting system for my game and I want the player to be able to preview the thing they want to craft.
Anyways I used some code that someone else had made and I made a module script out of it. I am making the module public as other users may want to allow players to rotate models inside viewport frames as well.
local viewportModelRotator = require(game.ReplicatedStorage.Module) -- replace "Module" with the name of the Viewport Model Rotator script
API
-- requires the module (duh)
local viewportModelRotator = require(game.ReplicatedStorage.Module) -- replace "Module" with the name of the Viewport Model Rotator script
-- enables viewport model rotation on a viewport frame
local rotationViewport = viewportModelRotator:Enable(path.to.viewport.frame.goes.here)
-- disables viewport model rotation on a viewport frame
rotationViewport:Disable()
Miscellaneous Stuff
To rotate a model inside a viewport frame you hold left click and drag your mouse (assuming viewport model rotation is enabled on the viewport frame).
If you change the model inside the viewport frame then you have to readable the module on the viewport frame.
It currently only works with models - the model has to have PrimaryPart set otherwise it won’t work.
Features im planning on adding so you guys don’t waste your time suggesting it in the replies
mobile and xbox support
configuration options - speed of rotation, axis that the model can rotate, button that triggers the rotation (xbox, mobile and pc)
SetPrimaryPartCFrame and GetPrimaryPartCFrame are being deprecated in favour of the new pivot APIs. PivotTo and GetPivot are the new functions to use for model space manipulation.
Hope they’ll be of use for future updates to your module.
I have improved this script, now all parts move smoothly as they should. You can also move the model vertically, but it won’t work perfectly. I hope I was able to help someone.
My version module script
local UserInputService = game:GetService("UserInputService")
local ButtonsHeld = {} -- Tracks buttons being held. Used to know when dragging
local LastMousePos = nil -- Used to calculate how far mouse has moved
local mouse = game.Players.LocalPlayer:GetMouse()
local viewportRotation = {}
viewportRotation.__index = viewportRotation
function viewportRotation:Enable(viewportFrame,sensitivity)
local viewportModel = viewportFrame:FindFirstChildWhichIsA("Model")
self.viewport = {
inputChanged = nil;
inputBegan = nil;
inputEnded = nil;
touchStarted = nil;
touchEnded = nil;
}
setmetatable(self.viewport, viewportRotation)
self.viewport.inputChanged = UserInputService.InputChanged:Connect(function(input, gameProcessedEvent)
if input.UserInputType == Enum.UserInputType.MouseMovement then -- runs every time mouse is moved
if ButtonsHeld["MouseButton1"] then -- makes sure player is holding down right click
local CurrentMousePos = Vector2.new(mouse.X,mouse.Y)
local change = (CurrentMousePos - LastMousePos)/sensitivity -- calculates distance mouse traveled (/5 to lower sensitivity)
-- The angles part is weird here because of how the cube happens to be oriented. The angles may differ for other sections
viewportModel:PivotTo(
viewportModel:GetPivot() * CFrame.Angles(math.rad(change.Y*-1),math.rad(change.X),0)
LastMousePos = CurrentMousePos
-- This line makes everything possible. The PrimaryPart's orientation DOES NOT move the rest of the model with it.
viewportModel:GetPivot()
end
elseif input.UserInputType == Enum.UserInputType.Touch then
if ButtonsHeld["Touch"] then
local CurrentMousePos = Vector2.new(mouse.X,mouse.Y)
local change = (CurrentMousePos - LastMousePos)/sensitivity -- calculates distance mouse traveled (/5 to lower sensitivity)
-- The angles part is weird here because of how the cube happens to be oriented. The angles may differ for other sections
viewportModel:PivotTo(
viewportModel:GetPivot() * CFrame.Angles(math.rad(change.Y*-1),math.rad(change.X),0)
)
LastMousePos = CurrentMousePos
-- This line makes everything possible. The PrimaryPart's orientation DOES NOT move the rest of the model with it.
viewportModel:GetPivot()
end
end
end)
self.viewport.inputBegan = UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
if input.UserInputType == Enum.UserInputType.MouseButton1 then -- player starts dragging
LastMousePos = Vector2.new(mouse.X, mouse.Y)
ButtonsHeld["MouseButton1"] = true
end
end)
self.viewport.inputEnded = UserInputService.InputEnded:Connect(function(input, gameProcessedEvent)
if input.UserInputType == Enum.UserInputType.MouseButton1 then -- player stops dragging
ButtonsHeld["MouseButton1"] = nil
LastMousePos = nil
end
end)
self.viewport.touchStarted = UserInputService.TouchStarted:Connect(function(input, gameProcessedEvent)
if input.UserInputType == Enum.UserInputType.Touch then -- player starts dragging
LastMousePos = Vector2.new(mouse.X, mouse.Y)
ButtonsHeld["Touch"] = true
end
end)
self.viewport.touchEnded = UserInputService.TouchEnded:Connect(function(input, gameProcessedEvent)
if input.UserInputType == Enum.UserInputType.Touch then -- player starts dragging
ButtonsHeld["Touch"] = nil
LastMousePos = nil
end
end)
return self.viewport
end
function viewportRotation:Disable(viewportFrame)
if self.viewport then
self.viewport.inputChanged:Disconnect()
self.viewport.inputBegan:Disconnect()
self.viewport.inputEnded:Disconnect()
self.viewport.touchStarted:Disconnect()
self.viewport.touchEnded:Disconnect()
end
end
return viewportRotation
Local script
-- requires the module (duh)
local viewportModelRotator = require(game.ReplicatedStorage.ViewportRotation) -- replace "Module" with the name of the Viewport Model Rotator script
-- enables viewport model rotation on a viewport frame
viewportModelRotator:Enable(script.Parent.ViewportFrame,1.5) -- path VieportFrame, value to lower sensitivity
-- disables viewport model rotation on a viewport frame
viewportModelRotator:Disable(script.Parent.ViewportFrame,1.5) - -- path VieportFrame, value to lower sensitivity
Edited:
I also fixed the API, now the turning is quietly turned off as it should be.
Edited 2:
Also been added mobile support but I don’t think that it’s will work very well.
Edited 3:
I fixed error when input disable