Godot 4.5 Tutorial: VHS Camcorder Shader & Atmosphere (Backrooms Part 3)
1113 segments
Right now, our game looks a little bit
scary, but it also looks too clean. It
looks like a 3D render. Now, to make it
feel real, we need to degrade it a bit.
We're going to shove this pristine 3D
world through a lens of the cheap 1990s
camcorder. Today, we're adding the VHS
effect. Welcome back to GDO Dev
Checkpoint. We have the maze and the
lighting. Today, we're going to focus on
post-processing. Think of it like
putting a filter over your camera lens.
We're going to add a camcorder UI
overlay and write a custom shader to
create that tape grain look. I'm
Spaghetti Syntax. Let's get building.
Before we mess with the video feed,
let's add the camcorder interface. We
need UI elements that stay stuck to the
screen no matter where we look. Now,
back in our project here, let's go to
the player scene here.
Turn on my highlighter. You can see
better.
Then we need to add a canvas layer node
as a player of the child. So we can
right click the child, add canvas layer
node, which is right there. Enter down
and rename it to camcorder UI. Camcorder
UI.
Now a canvas layer draws on top of a 3D
world like a sticker on your monitor.
You actually go to our 2D section here
and be able to see it better. The first
thing we'll do is add the record label.
Right click our camcorder UI. I'm going
to add a child node. It's going to be an
Hbox container.
Now, just organize things horizontally
for us. Create. And as a child of this
HBOX container, we're going to add child
node. We're going to use a label
right here.
We're going to name this to record
label.
And then with this record label
selected, we can rightclick, duplicate,
or press Ctrl D.
Perfect. Now we have two of them. Now in
the first record label, we're going to
use a dot. Now, not a period, but is a
dot with a space in front of it. Now I'm
going to include this down in the
description, so you can just copy it
from there. And then I'm going to paste
it into this text section. It looks just
Now, if you want to find it yourself,
you can actually find it in the
character map. If you go to your search
icon in your taskbar, if you're on
Windows, you can search for character
map. Just type in character map right
there.
Then
if you don't have advanced view up here,
you must go to Unicode,
search for Unicode 25 CF.
And that's the unic code for the dark
circle. Perfect. Now you can actually
select that, then copy it here.
Copy. And then you can paste it into
your window.
Since we already have it on there, I'm
gonna actually make a space here. V. And
now I have my dot. Great. Now I have
that. And we add the space in front of
it so it doesn't hug the wall too much.
And then on our second record label
here, we're going to add just the
letters rec.
Perfect. And for this record, we're
going to do here is we're going to go
down to theme overrides colors or change
the font color to red. I'll just go in
my linear, pull these all the way back.
And now I have it red. So the record
label should be red and the dot should
be white. Great. Now we're going to for
our camcorder UI, we're going to add
another child. With that selected, add
child node label.
I'm going to rename this one to time
stamp
label.
We're going to change the anchor to this
one to the bottom right.
That'll be down here. We get rid of this
output window.
And for this text we're going to use is
2701
1894.
And we're going to use the time of 10
32. Doesn't really matter what time you
use as long as we have the hour and the
minutes and the seconds. That's we're
going to access through script later.
Then we use an empty line here for
spacing on the bottom. We're going to
change our horizontal alignment to
right.
Then this little grabby thing here, I'm
going pull it over.
a little bit from the wall. It's not
hugging the wall so much
just as so it's not right on the the
line here. We kind of want it over a
little bit so it matches what it used to
look like on the camcorders.
All right. Now, we're going to go to our
assets folder. We're going to rightclick
and create a new folder.
We're going to call this fonts.
We need that old VHS fonts. Now, if you
downloaded it from my tutorial assets
Google Drive, you already have this
font. If you didn't do that and you want
to do it separately, it's this font here
on ddefont.com.
It's the VACR-OSD-mono.font.
And that's the one that the old
camcorders used to use. It is 100% free,
which is why I'm able to include it in
this assets pack that you can download.
But if you want to do it individually,
you can just download it from here. I'll
include all the links in the
description. And however way you decide
to get it, once you do have it, with the
font folder selected, after you get that
zip file extracted, we're going to drag
in the VCR OSD model font and import it.
There we go. You should have this folder
with the attribution text and the VCR
text. If you don't have the attribution,
that's the one I made in the Google
Drive folder. All it is saying is where
this font came from so it can be
properly credited. All right. All right.
And back in our time stamp label here,
what we can do
now that we have that, if we go to our
timestamp label,
we need to make a new label settings
here with a new label settings created.
Go into the resource and go into the
font. And in the font section, we're
going to drag and drop
our font that we have here.
And then we just need to go back up to
our record and our dot
and then do the same label settings.
Open label settings font. Drag and drop
the thought into there. And same with
the record label.
Scroll back up to label settings. Label
settings. Open that up. Font and the
VCR. Drop it in. Perfect. Nope. We
changed our record back to white. So we
change our color here now and pull these
down back to red. Perfect.
And we also want to make these bigger.
So with I'm going highlight all three of
these. I'm going to change the label
settings
of the font to 50.
That's only going to do the one. So
we'll do the record label. Change that
to 50 individually.
Then the time stamp label also 50.
Great. Now those are very legible just
like it would be on a old school camera
recorder.
So now we have our timestamp label here.
A static picture of a clock is not going
to cut it. If the player survives for 20
minutes, the clock needs to read 20
minutes later. And if they play through
midnight, well, we need this date to
change.
Now, we need to add a script to it. A
script that took me back to my college
days of writing scripts. We just need a
timer. Basically, a date time clock. So,
with our timestamp label node selected,
we're going to rightclick and we're
going to add a script. Not in the seeds
folder. We want to put it in a scripts
folder. Back up to our root scripts.
Next to the player JD GD script, we're
going to rename it to not timestamp
label. We're just going to rename it to
timestamp.gd.
Open and create.
All right. Now that open, go and save
the scene real quick and make this
bigger.
Now, as Habit says, I'm going to get rid
of this boilerplate code and start from
scratch.
with our extends label here. The first
thing we need is the start date settings
so they can be editable in the
inspector. So we want them editable in
inspector
and we need everything from the year,
month, day, hour, minute, and second. If
we want to change them, we need to have
access to them. So with the export var
year is going to be not year is going to
be an int and default we'll do just the
1994.
Oh let's actually change the year
rolling over. We'll do an 89 and then we
can do the export bar. Month is also
going to be an int. It's going to be the
12th month. Then at export var day it's
going to be another int and it'll be the
31st. So New Year's Eve at export var
hour our
he uses military time so it's easier
that way. We'll do var int is going to
be 23. said it's 11 p.m. So then export
var minute is going to be another int
that's going to be 59. So right before
it turns over to midnight. This way we
can change the month. We can test the
month and the year rollover.
So at export
bar for the uh second there's also going
to be an int. And we're going to have it
at 55 seconds. We have to wait five
seconds to be able to see if the
rollovers are working properly.
Then we also need a timer in the script
as well. So it's going to be our
internal timer
and our time is going to be it's going
to be bar time accumulator.
So that way we can
properly judge how long it's been. We'll
set that float to 0 0. And then we need
to actually check the days in the each
month because each month has a different
set of days. So how we do that days in
each month? Well, the first we're going
to do by index. So the index zero is
going to be January.
So you're going to be an array here.
And then we're just going to make an
array with days in months.
And then the array is going to contain
each month's day. So zero is January and
there's 31 days in January. February has
28. March 31st or 31 and then 30 days in
April and then we have May which is 31st
or 31. June is 30, July 31, August 31,
September 30. And then we have October
which is 31 but Halloween and November
is 30 and then December is 31. So these
are all 12 months in a row.
Now that we have those, we have our time
and we have our timer in the
script. So we could track the seconds
and then we have the days in each month
that's going to be appropriate.
We need to have a ready function. The
ready function is going to track
things like if you put your own in dates
in here because you can we'll be able to
actually do our dates in the inspector.
It's going to make sure the date you
entered is valid because we can't have
the user putting in a date that's not
valid. You could make it so you can't
edit this in the script. But even then,
if we want to if we edit it in the
script only, we still need to make sure
these dates are actually dates. If
they're not, it can break things like
our days in the month. So it's like a
safety check. So in the ready right in
the beginning, we need to do the safety
check
to verify the inspector input
before starting or even the script
input.
And we need to check if not
we're going to do a a function that
we're going to write in a second.
Is input valid?
Okay. Now after we have that we can go
into our if statement here. We need to
check for if this input is not valid
after we write that function. Well if
it's not then we need to throw an error.
So we use a thing called a push error.
Now, it's basically a custom error that
GDScript can use to push errors, custom
errors to the debugger console. Helps
track where the error comes from. So,
the error we're going to throw is called
invalid. We're going to have it say
invalid date entered.
It's going to show what the actual
date was that was entered. So, colon and
then quotation and concatenate to a
string. We're going to do the day and
then we're going to plus
there
I'm going to separate the day with the
month. So we're also going to use the
month and contain that string month.
Then this gets pretty long. So we can do
here is do the backspace
end for a new line. Enter down.
And then
we can enter over. And then what we need
now is the other string there. And we're
concatenate with that.
And we need a plus sign here.
Plus
there.
Great. Oh. Oh, it's just the backspace.
Sorry, not the backspace. N
the back slash. There we go.
Then after that we have the day month
and we need the year. So we'll do the
string. Turn the year into a string.
There we go. Now we have the date
entered string day string month. Then
the backslash no end. That's only within
use the backslash n like this inside of
a string here. But we don't use that
outside of the string. We just use the
backslash.
Great. But now that we know that we have
an invalid date, well, we need to set it
to a valid date. So our normal print
statement, we can say resetting
the clock.
Resetting clock
resetting clock to default. I like that.
Which is going to be December
December 31st,
1989.
But then we need to tell the year and
the date and the minute and the second
all that what that actually is. So our
default values are going to be default
back to safe values.
Okay. And we do that by saying the year
1989
and then the month is the one or not the
one 12 and then the day is 31
and then the hour is zero. No not zero
23
and the minute is going to be the 59. We
spell it right.
Then the second
55.
Then we're going to write this input
valid function.
We're also going to write after we've
checked that the date is correct. We
don't have to go into there. We're going
to if the date is correct, well, we're
just going to go straight into this new
label function that we're going to write
called update label.
Just like that. Now, let's write these
two functions. Now, we go out of the
ready function. Just enter down a couple
times. backspace to the wall.
Now, the first one, the update label
here, we're going to do some string
formatting.
We've never done that. I'll explain in a
second. So, you want to format
the label of the time stamp. It's going
to be day, month, year. So, two digits
for the day, two for the month, four for
the year.
And then after we have that, well, we
need the new line, which is going to be
the backspace n. And it's going to be
the hour, minutes, and seconds. So two,
two, and two. So how do we do that?
We're going to take the text.
The text is going to be the
is going to be the timestamp label text.
We only have to say text because it is
attached or should be attached attached.
Make this smaller to your timestamp
label. So we can just use text. Then
it'll access the inspector text right
here. I'll make this bigger again. And
since we're accessing the text here
directly
and equal that to a string format that
lets us change it dynamically. So with
the quotation marks we use a my modulo
which is also a percentage
sign we call modulo in programming. Now,
these act as placeholders for where we
want to dynamically put in strings. Like
for this one, this front one's going to
be the date here. That's where this
placeholder is going to be. And then
we're going to put in a zero to D. Now,
the D on the end acts as an integer. So,
it's going to be an integer placement.
And the zero means there should be zero
padding. There's fewer digits than the
specified width, which is two. because
the two sets the minimum field width to
two characters that keep it nice and
tidy. So we're going do that exact same
thing for the year or not the year, the
month. So we're just going to space over
do another modulo
right here and 0 2D. So that'll be our
month. And then for the year it's going
to be four digits. So we're just going
to use the placeholder modulo and then
the D. So we know it's integer but we're
not going to limit it to two.
And we don't have to limit it this way
at all. It'll just be four. And then we
need to do the new line. So it's a
backspace N. So that'll create a new
line. So it'll be down. If you remember
here, I'll make this smaller in our 2D.
We're going to do a new line right here.
And then it's going to be the time.
That's what we're going for. That's the
look visually. And we'll go back to the
script. Make this bigger.
Now that we have our date, we're going
to use our time. So after our new line,
we're going to do is well the same thing
all across the modulo zero 2d because
there's going to be two digits integers
all the way across. We need to make sure
they add these colons in here. So it' be
colon then modulo 0 to d. Great. Then
another colon modulo 0 tod. Great.
Then we need to add the modulo on the
end here. It's going to say, "Hey,
what are these things you want to put in
there?" And then this little bracket box
here like an array. Well, these this
first one here is going to be the day,
not the dar, the day. And the second one
is going to be the month. Third one is
going to be the year.
Then we can actually backspace down.
Then I'll enter. I'll bring it over and
then we can do the so it looks just like
it will on the screen is the hour, the
minute and the seconds
and a second.
No, I forgot my comma right there. There
we go. So, day, month here, hour,
minute, second. So, this day is going to
go into this section.
Month there, year there, hour, minute,
so on and so forth.
Great. Now that we have the update label
set up, let's do the make sure the input
is valid. So, we'll enter down a couple
times out of this one. Go back to the
wall. There we go. The function is going
to be called is input valid.
Make sure spelled just like we did up
here. And then we're going to go into
this one. Was it going to be a return?
Because this is checking yes or no. Is
this valid or is it not? So, it's a
bool. So it's going to be a arrow over.
So a dash and then the angle bracket
forward
enter bool. Okay, this is going to say
we need to return a bool. The first
thing we do, we'll just do return
uh true. There we go. That'll throw get
rid of all the errors. Now you know
we're on the right path.
But first go and save that. First thing
we need to do is check for simple
ranges. Check simple ranges.
So we need to check if the month is less
than one
or the month is greater than 12. Well,
we know that the months are wrong. So we
need to return false. So return false
right there. Now you can do it on a
single line like this or you can enter
down and make it like a normal statement
here. Since we're going to check some
pretty small stuff individually, we can
do is just keep it on the same line and
the syntax will read just the same.
It'll be a little bit cleaner. The next
thing we do is if the hour
is less than zero, well, that's wrong.
Or the hour is greater than 23. Well,
that's also wrong. So, military time 23
is the 11 p.m. Zero is the 12 a.m. So
then if that's not this or that, return
false.
And we're just doing some safety checks
is all these are. So just take your
minutes and then we need to know if
that's less than zero or the minute is
greater than 59.
This is also false.
Return false.
And then you want to check the
second. Yeah, we got hour, we got month,
hour, minute, second, month, hour,
minute, second. So if second is less
than zero or the second is greater than
59,
return false. So those are the easy
ones. Now the harder ones is check for
specific days
in a month. So we're going to check
for specific
days in a month or in any month. So the
var store variable for the max days it
can be is the days in the month
of the current not days and months days
and months width. There we go. This is
an array. We need to check which month
it is. So we're going to take the month
and then minus one because remember our
months are 1 through 12 but in the index
and array it'll be 0 through 11. So the
current month is actually the month
minus one because if it's month here
it's going to be month 10, right? But
it's going to be index 9 in the array.
And next we check well is it a leap
year? Now leap years are the ones every
four years which makes the days change
to make it even more complicated but
it's pretty straightforward. So var is
leap. So if it is a leap year well we
need to do the year. So whatever year it
is and we use the modulo operator which
is four because every four years is that
equal to zero.
And this is a standard formula for
finding a leap year. You can really find
this formula anywhere. So the way you do
that is check the year and then we're
going to do the modulo again get the
remainder divided by 100 then does not
equal zero.
So we know it's not a leap year with
that formula. The other one we use is or
the year
the modulo 400
there's no remainder equal to zero. So
it's saying there's no remainder on any
of those equations. So these are return
the true or false either or. So how do
we check for that? Well, we're just
going to do an if statement. So if the
month and the affected day affected
month is February for leap year.
So there's 28 days of normal ones and 29
on leap years. So if the month is
February, so it would be two.
And this leap we got from this formula
to check for a leap here
is leap. So I'll check if is leap is
true. Well, we need to change the max
days of the current month which is two
to 29 instead of 28. So just checking if
it's February
change the mac days max days to 29 but
only if it's a leap year. And next we
need to check again if we did change the
max days we're going to include that in
our day check. So if the day is less
than one like we did up here with the
hours and the months and now we're
checking for the day the day is less
than one or the day is greater than the
max days.
And now we have max days. Now if it's a
leap year change February to 29. So this
way if you just check the month here you
don't change the the days and remember
up here our 28 is the all the days we
put into February because 90% of the
time it will be 28 but the other 10% is
going to be a leap year. So to account
for that so we can use whatever date you
want. If the day is greater than max
days well that's also false. So we need
to return false.
Great. Now we have accounted for months
being wrong, hours being wrong, minutes,
seconds, then we accounted for leap
years in our days. Now the last thing we
need to check for is the year. And
actually, let's put the year on top. If
that's wrong, well, they're all wrong,
right? So if year is less than let's
just you can put it whatever you want
but we'll just do 1900 to make like a
camcorder goes into 1900s or wherever
you want to put it we can also then we
want to do the future too right so we'll
just do greater than 2100 for now so if
it is then we'll return false
great count for the year month second
days and a leap year the month is we'll
change the days. The month is a leap
year, we'll change the days. If it's the
days less than or greater than the max
days, return false. So, this should
account for everything.
Great. Now that we have all that, what
we can do here is need to
now that we're updating and we're
checking if it's valid. Well, we need to
make this time move. We do that in the
process function. down a couple times
underneath the ready and a couple above
the update label. We're going to use a
function process
and also run on the delta
which will
help us keep track of the time. We go
into that. We're use our time
accumulator
and we're going to use that to plus
equal delta. So that's going to keep
track of our seconds based on our frame
rate. So we do that for what this means
is every 1 second
every real time second we'll do that
every one real time second I'm going to
tick the clock
so if time accumulator
time accumulator there is
greater than one
greater than equal to one we know it's
been a second so our time accumulator
is going to go back down to zero by
minus to one there. There we go. That
way we know it's been a second. Then
we're going to reset it back to another
second. We're going to do call the
function. We're going to call this one
tick second. So now we know that it's
been a second. So we need to write a
function called ticksec. So once it's
been a second, we're going to enter down
a couple times and write this function
called tick second. Okay. Going to go
into that and say second plus one plus
equals one. So we're going to up our our
second label.
So then we handle the rollovers between
all of our seconds and our minutes and
our hours. So first one we're going to
do is handle time rollovers.
So when the time gets to where it needs
to be changed, first one is the second
of course. So the second is greater than
or equal to 60.
Well then we need to make the second
back to zero.
Then we need to actually after the
second is at 60 of them we need to up
the minute by one.
So then we need to check our minutes. If
the minute is greater than equal to how
many minutes in an hour? 60. Well we
need to set that back to zero. And then
we change the hour by one. There's that.
So then we check our hours. If the hour
hours in a day is 24, so if it's greater
than equal to 24, well that's going to
be zero. So back to the hour zero. So
that would be midnight. And then we need
to write a function after this to
actually take over the whole day. It's
going to be called tick day. Perfect.
Okay. And then we go into
Well, after we do that,
before we go into tick day, let's update
the label.
Perfect.
That'll update the label after we call
the tick day function. But then this
text tick second is complete.
So we'll go to the tick day function.
Now enter down a couple times. Backspace
to the wall. Then we're going to write a
function called tick the whole day.
Perfect. So our day go into there. Oh,
helps by a space right there. Then colon
enter down our day by one.
So the day also has to check for leap
years. So we need to check for the leap
year the day too.
So, and to make it more specific, every
four years. So, we write this down
unless
divided by 100 but not 400.
So, that's the equation for the leap
years. So, if you divide it by 100, it's
every four years. But if it's divisible
by 400, it's not. And once again, you
can find this equation anywhere really.
So we actually take our
function down here or our equation down
here. We can take that and we're just
going to use that again. Copy it. Crl +
C and we're going to paste it right
there because we need that again. And
then after that we need to have the
we're actually going to take the max
days as well. The max days we'll take
that line there. We can copy that and
then paste that because remember we also
need make sure the month one once again
just to specify the month is a onebased
index
one based index which means
this is 13 minus one or this be 12 - 1
11 is actually December in the index
because it starts at zero. Great. And
then after these two, we're actually
checking the same thing. If the month is
equal to February, so two and is leap
well, we're going to change the max days
to 29,
just like we did in the
is input valid function right here.
So when you're polishing or refactoring,
you can actually make this its own
separate function, but for now, we'll
just keep it in these separate ones
here. And after that we can check the
day. So if the day is greater than max
days,
well we want to make the day equal back
to one because we've rolled over the
whole month. Then after we do that, we
need to check make sure the month is
actually over by one. So if it's
February 28th or February 29th on a leap
year and the day goes up by one
and it's over the max days, then we're
going to change the month into the next
month. Hopefully that makes sense. Then
we check the month after we increment
the month to make sure it's not the 13th
month of the year because if it is, we
need to go back to January. So the month
is greater than 12 and the month back to
one, which is January. And then we're
going to change the year.
So the year is going to go up by one.
Perfect. There we go. And save that. Now
after all that,
we go back to our make this smaller. Go
back to our timestamp label. And we have
all these dates and months. Now we have,
if I go back to the world
in our 3D section here,
we're going to save it. If I play now
here, I can see our time stamp on the
bottom right. It's ticking up. And there
we go. Rolled over to midnight. Change
the date and the year. And that's all
this. And we're ticking up now. We
should probably bring this up a little
bit, but I'll leave it for now because
we're about to add that VHS shader,
which is going to change our viewport
settings.
And exit that. Then we can do a little
test here. If I go into
our timestamp label, let's check our
verification. I'll put an extra digit
here and make this the 13th. Well, this
won't even run because the it's going to
check the year first. So, if I added an
extra digit there and save it.
We can do here.
So, I just notice on this timestamp
label.
There we go. We do here is go into
script. I'm going to go down to make
this bigger.
And after our string formatting
here,
I'm going to add another new line there.
That way it puts that new line on the
bottom. And save that.
Enter there. And go back to my world
3D. Go and run the current scene.
And now we have our space down here.
There we go.
And we see our debugger flashed. Going
to exit that. And then we have our
custom
error. I entered a one on the end of
1989,
which means it's an invalid date.
Perfect. So, our check is working. Turn
that back to default. We have a space
here. We have this record here.
and the error console will yell at us
and reset the timeline to where it's
supposed to be. Now, before we add that
VHS shader, let's make our lights glow a
bit. Old cameras tend to blow out the
bright lights a little more than the
newer ones. So, let's turn on some glow
in our world environment and then kind
of replicate that look. So, back here in
our world scene here, we're going to go
up to our world environment.
down to the in our world environment
resource.
I'm going to minimize this stuff here.
I'm going to go down to glow. I'm going
turn that on. I'm going keep the
intensity at 0.8.
I'm going turn the bloom to 0.2.
Make it blow up a little bit. And to
accentuate that glow a little more, I'm
going do some volutric fog. Turn that
on. I'm going set this to 0.03. 03. So
you still see pretty far and it's not so
crazy. I'm going change the albido to
the same bright yellow as we have here
as the lights. And then the hex code for
that is FF E B0.
Well, that didn't take. Let's try that
again. FF E
B 0. There we go. Click. Press enter on
that. There we go. That's a slight
yellow. Perfect. Then I want to change
the emission to the same as this. I
actually copy that. Click on my
emission. Instead of black, we want that
yellow haze.
I want turn energy quite a bit. 0.5.
So it's not so crazy, but it gives that
eerie kind of smoky
long distance haze. Great. Now, that'll
give us some spooky
cinema, especially when we add that
shader.
Let's go and test that scene.
There's that. Now, we kind of have this
spooky fog. Give it more of an eerie
feel and these glowing lights. All
right,
you made it to the post-processing
setup. Now, we're about to add the VHS
shader. Post-processing in GDAU is done
by putting a flat rectangle over the
entire screen and applying material to
it. Now, we need a node that covers the
whole screen and it needs to sit on a
layer above the 3D world, but not below
our UI. So, back in our player scene
here,
we need a new canvas layer. So, we're
click on our player scene here, add
child node, canvas layer right there.
Double click. There we go. Once it's in
there, we're going to rename it to
postprocessing
layer.
And we need to add a color rect. So,
right click, add child to color rect.
Right there. I'm going to rename this to
VHS shader.
Just like that. And for this, we need to
take the anchors and apply it to the
whole screen. So, full wctck.
Now it should turn white and cover the
entire thing.
Then we need to take our camcorder UI.
What we're going to do is we're going to
drag it down and make it a child of the
VHS shader we just made. Just like that.
So right now we're looking at a white
rectangle. We need to tell GDAU to
render the 3D game onto this triangle
and then distort it. First thing we want
to make sure is that this doesn't
actually block our mouse inputs. So on
the VHS shader, we're going to go to
mouse here and make sure the filter here
says ignore. There we go. Go to save
that. If you don't do this, you won't be
able to click through like on our
interactions
or look around.
All right. After that, I'm going to go
to the file system here in my resources
folder
and we're going to right click in our
resources folder or on it and create new
and we're go to resource.
Then we're going to look for shader
which is right here. Once you have that
selected and create it and we're going
to create a new shader we're going to
call VHS shader.
There we go. and create it in the
resources folder. And now we have it
right here. Now for this shader, we're
not going to reinvent the wheel here.
You double click and open. It has a some
default code here. Click on this to up
it. There we go. But shaders include
lots of math and those kind of things.
They're really hard to kind of go over
line by line. And to be frank, there's
so many people that have done gorgeous
shaders. are so much better than I will
ever be at it. I've only written maybe
one or two by myself and you can't
really be good at everything and you
shouldn't be. Use the tools like this
open- source GDAU engine for example to
your advantage. So where I found the one
I'm using was on a website or is on a
website that has tons of shaders
available for GDO gdosshaders.com.
super resourceful stuff for here. This
old school VHS CRT monitor effect is the
one I went for. Now, unfortunately, this
is an older one. So, this is for GDAU 3.
So, this will actually not work. So, we
also found or I also found someone who
updated this exact VHS CRT minor effect
for GDO4 and they were nice enough to
actually change the variables and stuff
to work in GDO4.
Did not include the
the comments though. And I love having
the comments because as much as looking
through this and you'll probably be able
to figure it out, not having the
comments makes it a lot more mysterious.
So I took this code and these are all
you got to make sure
that the person who wrote it doesn't
mind if you use it for anything.
And this this original shader here, if
you look at the top,
put it under the CCO license. So you
feel free to use improve and change this
according to your needs which is what
we're going to do and that's perfect and
I appreciate the one who put it in GDO4
which is great. So we took this and I
put it on my GitHub and added the
comments and I also added the
inspector numbers we're going to use to
make it look like I had in the intro
video of the first video. So, in the co
in the description below, I'll have the
link to the VHS cam shader we're using
for this tutorial. And then you can also
check out gdosshaders.com and look at
all the other shaders they have because
they have tons. But you might have to
update a few because there's a lot for
GDAU 3. But once you you get to go to
this GitHub and you can actually copy
it. You go to the raw section here and
then you can actually just copy it.
Control A, copy. or you can actually
just
copy the RAW file right here. So once
you have it, we'll go into which I'll do
here. I'll copy RAW file and I'm going
to go into back into our project. And
with the VHS shader selected and we have
the window open here. I'm going A and
paste all of that in here. So now we
have the entire VHS shader imported with
the inspector
values we're going to use and all the
comments and the links to where it got
from. I'm going to save that. Crl S. I'm
going to make this smaller.
Then with the VHS shader selected,
I'm going to scroll down to
material
right here and the canvas item material.
This material is empty. I'm going to
drag this shader into this material
section and drop it. Now I'll close this
shader editor. Now we don't need it.
You'll see the default is just like a
TV. Now we do not want that. It's going
to be hard to play through. That's where
the shader settings come in. So the
material shader material open that up.
And we have a shader parameters here.
They have all these settings. Now, the
resolution we're going to use is like a
square resolution. The ones I thought
looked the best for now is 1024
by 768.
That's the one I decided there. That's
gives you that kind of square CRT look.
Anyway, but we also need to change this
resolution to match our project
settings. So, if we go to our project,
project project settings, and then our
window, we need to change this to match.
So 1024 by 768.
There we go.
Now we have that and close that.
You'll see the viewport matches here.
But GDAU can get kind of finicky and it
needs to actually reload the scene here.
So if you click
control S is for saving and save it.
Click back to the world scene and just
change our viewport. go back to the
player scene and then it'll match the
new settings we just put in. All right.
And the other settings we want to do,
I'm going to change the roll speed, I'm
going to change it to three.
And then the roll size, I put that at
seven.
And then the distort intensity, put that
at 0.01.
I scroll down to the disc color, I'm
going to turn that off. Then the warp
amount, I'm going to turn that to zero.
Don't want any of that warp. Then the
vignet intensity. I'm going turn that to
0.5.
Darken the edges a little bit. Oh, we
also need to add the overlay to on. I'll
add that to the GitHub a little later.
And that puts our
words where it should be. Oh, the other
one I missed was the aberration.
We don't want those words
so far over like that. We're going to
change it to 0.01.
We still have a little bit of that
coloration, but not such an extreme.
Now, all these are adjustable to however
you want. That's what I decided for this
tutorial. And if we go back to our Let
me save that. Go back to our world here.
And we're going to try the play.
Look at that. Instant nostalgia.
In the inspector under shader
parameters, you can tweak the scan line
count, grain, and the color bleed until
it feels right to you. Now, the
difference really is night and day. It's
no longer a geometry test. It's a piece
of found footage. The bright lights
combined with the dirty lens create a
perfect uncomfortable atmosphere.
Now, if you're following along, take a
screenshot of what you ended up looking
like and tag me on Blue Sky. I want to
see your level layouts and your cameras.
Now, we have the look, we have the
movement. Now, in the next video, we're
going to add some interactions. We'll
implement a raycast system so the player
can open doors and collect items. Now,
if you found this helpful at all or fun,
leave a comment on what your GDO game
dev goals are. Please like, subscribe,
and hit that notification bell. It
really helps out the channel. And thank
you to all our current and past Patreon
and coffee members. Your generous
support keeps the channel moving. Now,
if you want early access to tutorials,
source code, or suggesting future
tutorials, please consider becoming a
member yourself. The links are in the
description. I'm Spaghetti Syntax, and
remember, always stay curious, and I'll
see you at the next checkpoint.
Ask follow-up questions or revisit key timestamps.
The video tutorial details how to implement a retro VHS camcorder effect in a Godot game to make it feel more authentic. It covers creating a UI overlay with a record indicator and a dynamically updating timestamp, which includes script-based date and time rollovers and input validation. The tutorial also shows how to enhance the environment with glow and volumetric fog for a spooky atmosphere. The core VHS effect is achieved by applying a custom Godot 4 compatible shader to a full-screen ColorRect, with adjustments to resolution and various parameters like roll speed, distortion, and vignette, to transform the game's visual style into a 'found footage' aesthetic.
Videos recently processed by our community