Viewport Model Character Outfit Viewer Idle Animation Interactable Help

Hello, so as you can see:

I currently have an outfit viewer model that is scripted perfectly, but it’s missing one thing.

I don’t understand how to make the outfit (on the left), look almost realistic and real-time with idle animations. Also possibly allowing the users, to interact with the viewport frame to move the model like 3D.

Example of what I mean:

image

Basically make it look like the Avatar Catalog, allowing the players to turn it around and so forth like you would when editing your avatar.

How can I possibly achieve this?

Current coding -

local NPC = nil

----------------------------------[[ VIEWPORT PORTION ]]------------------------------

-- Settings
local OFFSET = CFrame.new(0,2.5,-7)

-- Services
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

-- Objects
local ViewPort = script.Parent.ImageLabel:WaitForChild("ViewportFrame")
local Camera = Instance.new("Camera")

ViewPort.CurrentCamera	= Camera

local ValidClasses = {
	["MeshPart"] = true; ["Part"] = true; ["Accoutrement"] = true;
	["Pants"] = true; ["Shirt"] = true;
	["Humanoid"] = true;
}

local RenderObjects = table.create(25)

local function RemoveObject(Object)
	local Clone = RenderObjects[Object]
	if not Clone then return nil end

	RenderObjects[Object] = nil
	if Clone.Parent:IsA("Accoutrement") then
		Clone.Parent:Destroy()
	else
		Clone:Destroy()
	end

	--print("Removed",Object)
end

local function AddObject(Object)
	if not ValidClasses[Object.ClassName] then
		return nil
	end

	-- Create clone, regardless of Archivable
	local a = Object.Archivable
	Object.Archivable = true
	local RenderClone = Object:Clone()
	Object.Archivable = a

	if Object.ClassName == "MeshPart" or Object.ClassName == "Part" then
		RenderObjects[Object] = RenderClone

	elseif Object:IsA("Accoutrement") then
		RenderObjects[Object.Handle] = RenderClone.Handle

	elseif Object.ClassName == "Humanoid" then
		--Disable all states. We only want it for clothing wrapping.
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.FallingDown,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Running,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.RunningNoPhysics,	false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Climbing,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.StrafingNoPhysics,	false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Ragdoll,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.GettingUp,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Jumping,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Landed,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Flying,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Freefall,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Seated,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding,	false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Dead,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Swimming,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Physics,				false)
		RenderClone.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
	end

	--print("Added",Object)

	return RenderClone
end

----------------------------------[[ EVENT PORTION ]]------------------------------


ShowUIEvent.OnClientEvent:Connect(function(NPCEvent) 
	
	
	NPC = NPCEvent
	WooshSound:Play()
	script.Parent.Visible = true
	
	----------------------------------[[ VIEWPORT PORTION ]]------------------------------
	
	
	RunService.Heartbeat:Connect(function()
		if (not NPC:FindFirstChild("HumanoidRootPart")) or (not ViewPort.Visible) then
			return nil
		end

		-- Update camera
		Camera.CFrame = CFrame.new(NPC.HumanoidRootPart.CFrame:ToWorldSpace(OFFSET).Position, NPC.HumanoidRootPart.Position)

		-- Update objects
		for Original, Clone in pairs(RenderObjects) do
			if Original and Original.Parent then
				Clone.CFrame = Original.CFrame
			else
				RemoveObject(Original)
			end
		end
	end)

	local function HandleChar()
		--warn("Handle char")

		table.clear(RenderObjects)
		ViewPort:ClearAllChildren()

		local Viewmodel = Instance.new("Model")
		Viewmodel.Name = "PlayerViewmodel"
		Viewmodel.Parent = ViewPort

		local CharObjects = NPC:GetDescendants()
		for i, Object in pairs(CharObjects) do
			local RenderClone = AddObject(Object)
			if RenderClone then
				RenderClone.Parent = Viewmodel
			end
		end

		NPC.DescendantAdded:Connect(function(NewObject)
			local RenderClone = AddObject(NewObject)
			if RenderClone then
				RenderClone.Parent = Viewmodel
			end
		end)
		NPC.DescendantRemoving:Connect(function(OldObject)
			RemoveObject(OldObject)
		end)
	end
	
	HandleChar()

	
	----------------------------------[[ ACCESSORIES PORTION ]]------------------------------
	

	
	for _, Child in ipairs(script.Parent.ScrollingFrame:GetChildren()) do
		if Child:IsA("Frame") then
			Child:Destroy()
		end
	end

	local Accessories = {}

	local Backs = NPC.Humanoid:WaitForChild("HumanoidDescription").BackAccessory
	local BacksTable = Backs:split(",")
	for _, Back in ipairs(BacksTable) do
		if Back ~= 0 then
			if tonumber(Back) then
				table.insert(Accessories, Back)
			end
		end
	end	

	local Face = NPC.Humanoid:WaitForChild("HumanoidDescription").FaceAccessory
	local FaceTable = Face:split(",")
	for _, FaceAC in ipairs(FaceTable) do
		if FaceAC ~= 0 then
			if tonumber(FaceAC) then
				table.insert(Accessories, FaceAC)
			end
		end
	end	

	local Fronts = NPC.Humanoid:WaitForChild("HumanoidDescription").FrontAccessory
	local FrontsTable = Fronts:split(",")
	for _, Front in ipairs(FrontsTable) do
		if Front ~= 0 then
			if tonumber(Front) then
				table.insert(Accessories, Front)
			end
		end	
	end

	local Hairs = NPC.Humanoid:WaitForChild("HumanoidDescription").HairAccessory
	local HairsTable = Hairs:split(",")
	for _, Hair in ipairs(HairsTable) do
		if Hair ~= 0 then
			if tonumber(Hair) then
				table.insert(Accessories, Hair)
			end
		end
	end

	local Hats = NPC.Humanoid:WaitForChild("HumanoidDescription").HatAccessory
	local HatsTable = Hats:split(",")
	for _, Hat in ipairs(HatsTable) do
		if Hat ~= 0 then
			if tonumber(Hat) then
				table.insert(Accessories, Hat)
			end
		end
	end

	local Necks = NPC.Humanoid:WaitForChild("HumanoidDescription").NeckAccessory
	local NecksTable = Necks:split(",")
	for _, Neck in ipairs(HatsTable) do
		if Neck ~= 0 then
			if tonumber(Neck) then
				table.insert(Accessories, Neck)
			end
		end
	end

	local Shoulders = NPC.Humanoid:WaitForChild("HumanoidDescription").ShouldersAccessory
	local ShouldersTable = Shoulders:split(",")
	for _, Shoulder in ipairs(ShouldersTable) do
		if Shoulder ~= 0 then
			if tonumber(Shoulder) then
				table.insert(Accessories, Shoulder)
			end
		end
	end

	local Waists = NPC.Humanoid:WaitForChild("HumanoidDescription").WaistAccessory
	local WaistsTable = Waists:split(",")
	for _, Waist in ipairs(WaistsTable) do
		if Waist ~=  0 then
			if tonumber(Waist) then
				table.insert(Accessories, Waist)
			end
		end
	end

	local Face = NPC.Humanoid:WaitForChild("HumanoidDescription").Face
	if tonumber(Face) then
		table.insert(Accessories, Face)
	end	

	local Shirt = NPC.Humanoid:WaitForChild("HumanoidDescription").Shirt
	if tonumber(Shirt) then
		table.insert(Accessories, Shirt)
	end	

	local Pants = NPC.Humanoid:WaitForChild("HumanoidDescription").Pants
	if tonumber(Pants) then
		table.insert(Accessories, Pants)
	end	

	local GraphicTShirt = NPC.Humanoid:WaitForChild("HumanoidDescription").GraphicTShirt
	if tonumber(GraphicTShirt) then
		table.insert(Accessories, GraphicTShirt)
	end	

	local AddedTable = {}

	for _, ID in ipairs(Accessories) do
		if ID ~= 0 then
			if tonumber(ID) then
				if not table.find(AddedTable, ID) then
					table.insert(AddedTable, ID)
					local Template = script.Template

					local NewTemplate = Template:Clone()
					NewTemplate.ProductIDVal.Value = ID
					NewTemplate.AssetIcon.Image = "https://www.roblox.com/asset-thumbnail/image?assetId=" .. ID .. "&width=420&height=420&format=png"

					NewTemplate.Parent = script.Parent.ScrollingFrame
				end
			end
		end
	end
	
end)
1 Like

Take the mouse input using userinputservice and rotate the character inside of the viewportframe instead of the camera.

1 Like

I tried two ways-

One. Just rotating the model -

Runs.RenderStepped:Connect(function()
		local modelCframe = NPC:GetPrimaryPartCFrame()
		modelCframe *= CFrame.Angles(0,0.05,0)
		NPC:SetPrimaryPartCFrame(modelCframe)
	end)

But it seems to just be a stuck character in the viewport frame…

Two. A ViewportRotation Module -
viewportModelRotator:Enable(ViewPort,1.5)

As well as NPC = NPCEvent:Clone() trying to Clone the character to see fi that made a difference. It did because now the model on the stand is not spinning, but still doesn’t show in the viewport? Using option 1.

How can I fix this? Seems to just be a stuck character for spinning, but then rotator works but also acts stuck as well.

2 Likes