1-Bit Graphics In Unity | Obra Dinn Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
The Return of the Obra Dinn is an indie game classic with a unique art-style that (unlike some video games) isn't patented so you can replicate and change it all you want. Isn't the free exchange of ideas and concepts fun? Today I'm using the Built-in Render Pipeline to implement this effect. It's not hard to port over to the new Scriptable Render Pipeline but it is so much simpler to add effects this way. Just write a script with the OnRenderImage method and call Graphics.Blit(). The material parameter here contains the shader for the effect, found almost entirely within the Frag function. We write a shader that takes the MainTex parameter as our screen input and a Noise texture as our filter. You see, this cross-hatching effect where we use two colours to represent a gradient is called "Dithering" and it's been around in Image Processing for a long time. It works by applying a noise texture across a greyscale image, then comparing each pixel in the image with its respective pixel in the noise. If the image pixel has a large value than the noise value, that's a 1, otherwise it's a 0. Hence the name "1-bit graphics". These are represented by whichever two colours you like. Converting a colour into greyscale is simple, you just multiply out its components using the dot product like so. Finding the respective pixel in our noise filter, is also simple, we just divide the screen coordinates by the size of the noise texture and multiply the result by the size of the screen. Yes, this is a division, don't question it. Check against the image pixel like so and boom we've got a Dither Effect. But... ew... This is a problem. As we move our camera around, the dither texture and the environment around us don't match up, as they're being checked in Screen Space. We need a better way to sample our noise. Luckily, Lucas Pope, the creator of Obra Dinn wrote extensive blog posts about his development of the game, and one such blog post documents his solution for this exact problem. He got some okay results offsetting the noise by the amount the Camera has rotated and this is the method most recreations use but his best results were by projecting the texture onto a sphere around the Player's camera. Unfortunately projecting a 2D texture onto a 3D sphere, or vice versa, is an incredibly difficult task... (Just ask anyone whose tried to successfully map the Earth) And Lucas Pope doesn't divulge which projection method he uses (though he refers to it as "rings", whatever that means) He also suggests that you could change the noise texture into a shape that can tile around a sphere like a hexagon but everyone knows that you can't actually tile a sphere with hexagons as there will always be 12 pentagons at the corners of the icosahedron which EULER PROVED IN THE 1700S AND WE ARE STILL GETTING WR- My producers have informed me that I have to cut the 5-minute rant about tiling hexagons around a sphere but long story short we're going to have to find a projection ourselves. No more hand-holding. The first step is to figure out what point of the sphere each pixel is on. This took some time to get right but the gist is to calculate the camera's frustrum (that's the 4 corners of the camera's view) and lerp between them based on the screen coordinates. Now we've got our point on the sphere, we need to map it to our 2D texture. The key measure of quality here is how evenly spaced the pixels of the texture are. We want it nice and uniform. I tried a cylinder mapping but this was too small at the corners. *coding interlude* I used a UV sphere mapping but it was the same problem at the poles. *coding interlude* Finally, I settled on a cubic mapping, the kind you might find on a Skybox. This can be a little warped at the corners but for the most part performs very well. *coding intensifies* For the best results, we use this mapping at 2x the resolution we want to end up with and then downsample the image with bilinear filtering to smooth out those rough edges The small problem is that we no longer have a 1-bit output now, and as we downsample the image we're inviting a few dozen shades of grey. Some *coughs* other tutorials will say this is a necessary compromise and Lucas Pope himself doesn't stick to the 1-bit aesthetic. But simply looking a screenshot of the game in photoshop will disprove that theory. Luckily, the solution also lies within Pope's blog posts. We just need a simple thresholding shader for the final Blit. Now, the dither sticks perfectly as you rotate around and any distortion when moving is negligible. The final pieces of Pope's effect are an edge detection filter and how he changes between 2 different noise textures depending on the surface. An early blog post explains how he does this, using a custom surface shader to convert all lighting to the blue channel, the type of dithering to the alpha channel and reserving the red and green channels for vertex colours so that each face can be differentiated. But I don't need show an example of that ri- *BIG CODING INTERLUDE* *sighs* Okay, its sometime later and I've implemented it. Looks pretty neat. Uses this fairly simple surface shader and "minor" changes to the code. I just manually set the vertex colours in this scene, but Pope used a tool to randomly set and then adjust them. Check my project files if you need more information. The effect is now complete. The package I'm using for my First Person controller is called The First Person by the wonderful and amazing Breogán Hackett. Unity's standard asset controllers are long past their prime and this is a fantastic alternative that is easy to modify and even has support for Third Person cameras! Finally, this effect wouldn't be possible if Lucas Pope hadn't been so open in the development of his game. While it's cool to recreate it, I do recommend iterating and improving upon the style, helping make it your own. Here are some my experiments with retaining colour values in the dither or using different methods to calculate the threshold in the first place. Mess around with it and have fun! Like and subscribe and thanks for stopping by! This video wouldn't be possible if it wasn't for my patrons. Of course, I don't have any so I've hooked up a credits sequence to a random name generator. I'm taking this opportunity to announce that I got a job as a Junior Game Programmer! From what I can gather, the custom is to keep the studio secret until your first day but the bad news is that I likely won't have time to make tutorials after I start. My plan is to finish off Pixelsmith and make a few more videos before that happens, but after that, the only videos that go on this channel will most likely be of the video essay variety. This has been a fantastic experience and massively helped me put my game programming skills to use over the pandemic. All the comments I've received have been wonderful and feel free to email me or comment down below if you need any help with any of the concepts I talk about in these videos. I look forward to seeing what you all come up with! See you next time!
Info
Channel: Madalaski
Views: 47,313
Rating: undefined out of 5
Keywords: obra dinn shader, obra dinn tutorial, gamedev, game development, obra dinn in unity, obra dinn c#, obra dinn, 1-bit, dither, unity, unity3d, unity 2021, unity tutorial, how to make games
Id: Ap4fXGTOb7I
Channel Id: undefined
Length: 6min 19sec (379 seconds)
Published: Fri Mar 05 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.