Hello guys! I’m Pew, and this is part 3 of the series in which I explain how I work as a VFX artist!
I didn’t have much to talk about in the past few days, hence the gap between this and the last post.
Without further ado, this is the showcase video:
Today, I’d like to cover how I made the cutscene and the smoke in the back, which was a cheap excuse to use what I call “Mesh Flipbooks”.
Firstly, let’s focus on making the cutscene. We’ll use logic from the first part of this series, where I mentioned welding parts to the player’s HRP and treating them like limbs to animate them.
In short, we weld a part to the rig and animate that part as if it were our camera.
If you use Moon Animator 2 like I do, you could use the built-in camera and its “AttachToPart” property to attach it to said part, letting you easily preview the cutscene.
Now, if you export the animation with the camera part, you can attach a part with the same name as the one in the rig to the player, and it should get animated correctly.
You can use RunService to constantly set the player’s camera CFrame to the part’s CFrame.
Here’s some pseudocode for this:
local camera = workspace.CurrentCamera
local AnimTrack: AnimationTrack -- This reprsents your animation.
local CameraPart: Part -- This represents the camera part
local Connection -- This variable represents the connection, so you can disconnect it later.
Connection = game:GetService("RunService").Stepped:Connect(function()
camera.CFrame = CameraPart.CFrame -- Set the camera's CFrame to the part's CFrame
end)
AnimTrack.Ended:Once(function()
Connection:Disconnect()
end)
You can also use Animation Events to connect and disconnect the camera whenever you like.
Also, keep in mind that workspace.CurrentCamera
is meant to be used on the client. Passing objects like animation tracks or cameras through remote events doesn’t work, so you’ll have to figure out your workarounds.
You might also encounter an issue where calling the cutscene with shiftlock on makes the camera spin rapidly. This is because even if the player’s HRP is anchored, they can still rotate with shiftlock on the client. Surprisingly, the fix is very simple. All you need to do is disable AutoRotate
on the humanoid for the duration of the cutscene.
Now let’s move on to the “mesh flipbooks” I mentioned.
I recommend that you use the new asset manager beta feature for this.
Flipbooks are particles that have a spritesheet texture. The individual sprites in the spritesheet are looped over, creating the illusion of an animated texture.
Although you can’t directly use spritesheets on meshes, you can split the spritesheet into separate textures with a program like this, which is what I use.
You’ll need to import the spliced frames into Studio, select the frames, and insert the images. Keep in mind, you should number the frames’ names in order.
I recommend you put the inserted decals under a part and put it in a folder in the workspace. This will keep the decals loaded at all times, so there won’t be any flickering in the animation.
Here’s some pseudocode that runs the animation
local Textures = Folder:GetChildren() -- This will be the folder full of your decals
local Mesh = workspace.Mesh -- This will be the mesh you want to animate the texture on
local Duration = 1
local Framerate = 60
table.sort(frames, function(a, b) return a.Name < b.Name end) -- Sorting the decals by name, just in case.
for _, v in Textures do
Mesh.TextureID = v.Texture -- Apply the texture to the mesh
task.wait(Duration / Framerate) -- Alternatively, if you want he animation to last as long as the duration, divide by "#Textures"
end
This is everything I wanted to say today.
If you have any questions, corrections, or feedback about the effect I made (I know, it’s really mid) or this post, I absolutely encourage discussion.
Thanks a lot for reading!