**What do you want to achieve?
I want my vehicle models in my viewportframes to be rotated and oriented correctly in a consistent position. I have a dedicated viewporthandler modulescript to create and cache viewports for the vehicle models.
2. What is the issue? Include screenshots / videos if possible!
One of my viewports for one of my vehicles is rotated incorrectly and facing the wrong way.
The issue is the body mesh of the transport jeep model. Without the mesh, its positioned normally, but with it, it’s messed up like in the image
3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
I tried to update the script to rotate the model using the vehicle’s chassis, I tried turning the viewport camera (though I’m not sure if I did it right), I tried setting attributes on problematic vehicles that needs the model’s CFrame to be forcibly rotated. Nothing works and I dont know how to fix this.
Please help, thank you!
local VehicleViewportModule = {}
local RunService = game:GetService("RunService")
local CONFIG = {
DEFAULT_ROTATION = 0,
ZOOM_FACTORS = {
DEFAULT = 0.9,
CIVILIAN = 0.9,
ADVANCED = 0.85,
GAMEPASS = 0.95
}
}
local modelCache = {}
local rotationConnections = {}
-- List of core parts that shouldn't affect orientation
local CORE_PARTS = {
"Chassis",
"DriverSeat",
"SteeringRack",
"AntiRollBar",
"DirectionPart"
}
local function cleanModel(model)
-- Remove scripts
for _, child in ipairs(model:GetDescendants()) do
if child:IsA("Script") or child:IsA("LocalScript") or child:IsA("ModuleScript") then
child:Destroy()
end
end
-- Remove joints
for _, child in ipairs(model:GetDescendants()) do
if child:IsA("JointInstance") or child:IsA("Motor") or child:IsA("Motor6D") or
child:IsA("Weld") or child:IsA("WeldConstraint") or child:IsA("ManualWeld") then
child:Destroy()
end
end
-- Clean up non-core parts for special direction models
if model:GetAttribute("SpecialDirection") then
for _, child in ipairs(model:GetChildren()) do
if child:IsA("BasePart") then
local isCorePart = false
for _, corePart in ipairs(CORE_PARTS) do
if child.Name == corePart then
isCorePart = true
break
end
end
if not isCorePart then
child:Destroy()
end
end
end
end
end
local function setModelDirection(model, originalModel)
if originalModel:GetAttribute("SpecialDirection") then
local directionPart = model:FindFirstChild("DirectionPart")
if directionPart then
model:PivotTo(CFrame.new() * directionPart.CFrame.Rotation)
directionPart:Destroy()
end
else
model:PivotTo(CFrame.new())
end
end
function VehicleViewportModule.createPreview(viewportFrame, vehicleModel)
local existingConnection = rotationConnections[viewportFrame]
if existingConnection then
existingConnection:Disconnect()
rotationConnections[viewportFrame] = nil
end
local cacheKey = vehicleModel:GetFullName()
if not modelCache[cacheKey] then
local displayModel = Instance.new("Model")
for _, child in pairs(vehicleModel:GetChildren()) do
if not (child:IsA("Script") or child:IsA("LocalScript") or child:IsA("ModuleScript")) then
local clone = child:Clone()
clone.Parent = displayModel
end
end
cleanModel(displayModel)
setModelDirection(displayModel, vehicleModel)
local vehicleType = vehicleModel:GetAttribute("VehicleType") or "DEFAULT"
local zoomFactor = CONFIG.ZOOM_FACTORS[vehicleType] or CONFIG.ZOOM_FACTORS.DEFAULT
local modelSize = displayModel:GetExtentsSize()
local cameraOffset = modelSize.Magnitude * zoomFactor
local cameraSettings = {
CFrame = CFrame.new(
Vector3.new(cameraOffset, cameraOffset / 2, cameraOffset),
Vector3.new(0, 0, 0)
)
}
modelCache[cacheKey] = {
model = displayModel,
cameraSettings = cameraSettings
}
end
for _, child in pairs(viewportFrame:GetChildren()) do
child:Destroy()
end
local cachedData = modelCache[cacheKey]
local modelClone = cachedData.model:Clone()
modelClone.Parent = viewportFrame
local camera = Instance.new("Camera")
camera.CFrame = cachedData.cameraSettings.CFrame
camera.Parent = viewportFrame
viewportFrame.CurrentCamera = camera
local rotationAngle = 0
rotationConnections[viewportFrame] = RunService.RenderStepped:Connect(function(deltaTime)
if not modelClone or not modelClone.Parent then
local connection = rotationConnections[viewportFrame]
if connection then
connection:Disconnect()
rotationConnections[viewportFrame] = nil
end
return
end
rotationAngle = rotationAngle + deltaTime * 0.5
pcall(function()
modelClone:PivotTo(CFrame.new() * CFrame.Angles(0, rotationAngle, 0))
end)
end)
end
function VehicleViewportModule.preloadVehicles(vehiclesList, vehiclesFolder)
for _, vehicleName in pairs(vehiclesList) do
local vehicle = vehiclesFolder:FindFirstChild(vehicleName)
if vehicle then
local dummyViewport = Instance.new("ViewportFrame")
VehicleViewportModule.createPreview(dummyViewport, vehicle)
dummyViewport:Destroy()
end
end
end
function VehicleViewportModule.clearCache()
for viewportFrame, connection in pairs(rotationConnections) do
if connection then
connection:Disconnect()
end
end
table.clear(rotationConnections)
table.clear(modelCache)
end
return VehicleViewportModule
Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.