ViewportFrame Handler - Custom updating objects & humanoids in VPFs

Example:

The most common use for my camera system was camera systems for concerts.

With a few minutes, 20 lines of code, and a free model DJ set, this handler let me set up a simple camera system.

DJ_Example

Code:

local ViewportHandler = require(script.ViewportHandler)

local Frame = script.Parent.ViewportFrame

wait(2)
local c = Instance.new("Camera")
 c.CFrame = workspace.CamPart.CFrame
Frame.CurrentCamera = c

local VF_Handler = ViewportHandler.new(Frame)

local baseplate_Handler = VF_Handler:RenderObject(workspace.Baseplate)
local part_Handler = VF_Handler:RenderObject(workspace.Part,20)
local char_Handler = VF_Handler:RenderHumanoid(game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait())

for i,d in pairs(workspace.DJ:GetDescendants()) do
	if d:IsA("BasePart") then
		VF_Handler:RenderObject(d)
	end
end
71 Likes

Finally got around to recreating my camera system with this module. Anyone using the old camera system should switch!
This demo should help people understand how to implement this module.

16 Likes

This is really nice, and effective when needed.

5 Likes

Excellent job on your ViewportFrame scripts! It’s not that easy to script, so I appreciate you made this. Really nice work.

2 Likes

Made a cool flashbang effect using this.

Does the whole “burns the image to your eyes” thing.

Creates all the object handlers with an FPS of 0, and then calls the ViewportHandler:Refresh() when it wants to burn the image.

44 Likes

Update!

Added the Object APIs into the Handler APIs, allowing you to handle all objects at once without having to store all your Obj_Handlers and loop through each one to call their function.

Could you possibly open-source this? :o

1 Like

Using this module for it is overkill and actually wastes CPU.

I’ll make a Screenshot module or something that’s specifically designed for this, and open source that.
I’ll fix this module to work better in these cases.

1 Like

Made a pretty awesome change to the module.

Although still perhaps overkill, it no longer wastes CPU.


The issue:

The reason it was wasting CPU was very simple.

Every frame we iterate over every part and check if it needs to be updated. There are no parts that were active (aka everything was 0 FPS and being refreshed manually when burning the image), so we always iterated through them all and did nothing but update some numbers in them.


This was my initial change in an attempt to solve the issue. I've removed this, for reasons discussed in the end of this dropdown.

I made a simple(ish) change.

function ViewportHandler:_ValidateRefresher()

Anytime you make a change to the handler or an object within the handler, this gets called.

This function goes through all the objects. If there’s an active object, we make sure we have our binding to renderstep. If there are no active objects (such as our flashbang case), we remove that binding.

This way, when no objects are active, there’s no iteration happening.


Why I removed this:

There’s still a downside: if you have even one object active, it iterates through all the inactive ones too.
My final solution fixed this, and also reduces the cost of the module since it doesn’t need to call :_ValidateRefresher() all the time.

The solution:

Instead of iterating over every part, we only iterate over the active ones!

We now have 2 dictionaries: AllObjects and ObjectsRenderQueue.
When an object is inactive, it’s removed from the render queue, and added back in when made active again.

Our render logic only iterates through the render queue, which is empty in the flashbang case.

This also makes our render logic faster in it of itself, since it no longer has to check if the object is active. If it’s in that queue, we know it is!


This is a huge performance gain.

The previous version would be impacted by static objects. In our flashbang example, everything was static. But it matters in other uses too! If you have a large static map, you’d have rendered them at 0 FPS too! Now that won’t crush your performance!

2 Likes

Small change.

No longer uses BindToRenderStep. Connects to .Heartbeat instead.

Doesn’t affect much, but it allows it to run in parallel to the frame drawing so it shouldn’t drastically affect your game’s FPS.

2 Likes

Is that cheaper to run on the server?

ViewportFrames and frame rendering are client processes.

4 Likes

Is there a way you could provide a coding example of how the flashbang or “burn” effect was made? I tried doing it myself, but I can’t seem to wrap my head around it :^(

1 Like

So from this brief explanation, I’m copying the entire world? Ok

You should only really copy what you need to. You can see the Security Camera example, or open a linked topic if you require more help.

1 Like

What if I would make live interactive concerts with those cameras :thinking::thinking::thinking::thinking:

2 Likes

Sorry to bother you kind sir but I have a couple questions:

  1. Heartbeat vs Stepped or .Changed
  2. if RunService then would it be best to have 1 Heartbeat or Stepped connection managing all the new viewports or 1 per viewport

You’re making history my guy, keep up the great effort! I wouldn’t look for guidance for Viewport Frame’s from anyone else other than you.

3 Likes

Hey boatbomber, I was wondering why my humanoid animations (AnimationTrack) wouldn’t play in ViewportFrames. Does this module allow me to animate Humanoid objects with them? I’m curious to see what the Humanoid handlers do.

If it does, then I’d be really glad, since I’m still looking for solutions to this (very) annoying problem. All of your open-source projects are awesome and I’m looking forward to an answer.

1 Like