Gaussian Blur Post Process in Unity 2021 URP

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this video is sponsored by unity blur is an extremely useful and standard technique that all technical artists should keep in their books of Tricks Unity surprisingly doesn't include any blur effect of its own except for the depth of field which is a blur based on distance so it's up to us to make our own I'll be creating a post-processing effect for urp in this video and I'm working with unity 2021. in my last video I used Unity 2022's full screen Shader graph to make a post-processed outline effect this time however I'll be using good old code not just because I want to show the difference between using code and using full screen Shader graph but because full screen doesn't yet support multi-pass shaders and spoiler alert I'm going to use a two pass Shader for my blur effect on that note Unity 2022 LTS is coming soon and it's bringing a whole bunch of new features and improvements that you might have already seen in the unity 2022 Tech stream unsurprisingly I'm mostly looking forward to the new graphics features coming to urp especially official supports for custom post-processing effects with full screen pass renderer feature and full screen Shader graph but also stuff like LOD cross feed which is going to make visual transitions between lods a whole lot smoother over on hdrp you've also got the new portal system which looks gorgeous and easy to use there's a Unity blog post all about the LTS switch you should go check out there might be something there that interests you on top of the graphic stuff it's linked in the description right let's get started by looking at what a gaussian blur actually is the gaussian curve looks like this and it's described by an equation that looks like this if you increase the sigma value the standard deviation then it'll get stretched outwards and if you increase the view value this fancy little Hue here which is the mean the whole curve moves to the right it's symmetrical and these Tails technically never touch the axis but they get very close you might have heard people call it a bell Turf before you can extend it into three dimensions too and it sort of looks like you've draped a tablecloth over something but how does this help us to create a blur effect well here we have an image for each pixel of the image we can overlay a grid of weight values based on the gaussian curve so there's a large weight in the center that gets smaller as you go outwards then multiplying the colors of the pixels with their corresponding weight value then we sum the new colors and assign the result back to the center pixel on a new image you move the grid to the next pixel you do the same until eventually the new image contains a blurred version of the first image this process of overlaying the Grint over every pixel like this is called convolution and the idea is that the weights sum to one so you end up mixing mostly the centrifixal color with bits of the nearby pixel colors which results in a blurred image the result depends on the shape of the gaussian curve higher spread which gives us a flatter shape means there's more blur there's an alternative called box blur where instead of gaussian values you use 1 over the number of grid pixels as the wheat for every pixel but but it doesn't look as nice as gaussian blur in my opinion a nice property of the gaussian blur and the Box blur actually is that it is linearly separable instead of say using a three by three grit over each pixel which requires nine calculations we can use a three by one grid and run it across the image horizontally then run the same three by one grid across the resulting image vertically and we end up with an identical result with only six calculations per pixel in theory the grid would have to be infinitely large because if you remember the gaussian curve never touches the axis so all these pixels out here have tiny but non-zero weights in practice these weights are so close to zero we can ignore most of them I found that a grid size of about six times Sigma Works which Wikipedia apparently agrees with thanks Wikipedia then I'll round up to next odd number because R grid needs a center pixel let's now dive into unity and implement the blur post-processing effects in your opinion to put it bluntly are needlessly complicated in code but it's the best we've got if you need more control than Unity 2022's full screen Shader graph urp renderer features are the magic source that power post-processing effects in urp including those in my Snapshot shaders Pro asset pack we do need that control because we need two passes I am going to write three scripts and one Shader blur settings holds the Shader properties that we can tweak to our liking blur renderer feature handles injecting our custom code into the rendering Loop and blur render pass deals with creating the render textures and actually running a material over the image then of course as the blur Shader file which contains the horizontal and vertical passes that's a lot to get through start by creating a new c-sharp script and right clicking and going to create C sharp script and name it blur settings first we'll need to import a couple of extra namespaces unity engine.rendering and unity engine.rendering.universal I hope that self explanatory then I'll change the inheritance of the script from Model Behavior to volume components and I post process components a volume component is going to make rfx compatible with the volume system whereby we can choose to make the effect run globally or only within a certain collider without it the blur would just run all the time which we probably don't want we'll need to add a couple of attributes so that we're able to choose our blur effect in the volume effect drop down so add system.serializable and volume component menu with whatever path you want you can include folders in the name but I'm just going to stick with blur this script is where we need to add our properties that control the behavior of the blur effect we only need one property to control the shape of the gaussian curve I am going to make it a public clamped float parameter named strength this takes three parameters the initial float value and minimum and maximum values in the inspector this will be represented as a slider that can only take on values between the Min and the max I'll set the default as zero and clamp it between 0 and 10. it's good practice to set your properties to a neutral default value so you don't add the effects to your game and then suddenly get a jarring visual change there are other kinds of parameter type if you need them clamped or otherwise like in parameter color parameter texture parameter and so on try and clamp them if you can so you don't get people trying to set a strength value of 5 million the i-pose process component interface requires us to add two method called is active and is tile compatible in Visual Studio you can use this little icon to automatically happen is active is used to determine whether the effect uses valid variable values so in this case the effect should run only if the strength is above zero we also have access to a Boolean value called active which is true if the effect is ticks on and Force if not so we'll include that here the other method is called is tile compatible and I'm not entirely sure what it does unity says if it can run on tile which I figured might have something to do with tile based rendering on certain gpus but it's also not obsolete for Unity 2023 and onwards so if Unity are planning on throwing it in the bin it can't be that important I just return false and don't look back and it hasn't broken anything so far thus the blur setting script done so we'll move on to the largest of the three scripts Bligh render pass we need to import the same namespaces as before and this time the inherited type is scriptable render pass this script is the brain of our effects as it handles creating textures and materials and it tells Unity how to apply the effect this class requires us to override just one method called execute but we will optionally also override configure and frame cleanup I'm also going to add my own method called setup this script requires a few variables all of which can stay private a material which will hold our blur Shader a reference to our blast settings a render Target identifier called source which is basically the screen texture before we apply our Shader a render Target handle called blur attacks which is an intermediate texture which holds the results of the first of our two blur passes and an INT called blurtex ID which I'll explain shortly the setup method comes fast it does some one time setup for things that need to be ready before blur render Parts can do anything but it needs access to a scriptable renderer object which Christ does so many types to keep track of the similar names the scriptable renderer object is the glue that holds together all the features supported by the renderer the lighting and the textures output by the camera in our setup method we'll retrieve the camera color targets from the renderer which is the camera output texture we'll grab a reference to our blur settings script from the volume manager if you have several volumes in your scene using a blur effect then this get component method gets the correct one next we'll set the render pass event essentially we can make our blur effects run at a handful of predetermined points in the rendering Loop for a post-processing effect like we're making you will pick either before rendering post-processing or after rendering post-processing which are confusing names because we are doing post processing but the before and after in these names are referring to urp's already included post-processing effects like bloom or depth of field I am choosing before but if you're ever writing an effect and it doesn't work swap it to after and that sometimes makes all the scary bugs go away lastly we'll create a material to run our Shader but first we need to check that blur settings is not null meaning the camera is inserted volume which contains a blur effect and that the effect is active it has a strength above zero if so we'll find the Shader using its name obviously we haven't written the Shader yet but post-processing slash blur is the name I will be using you might have noticed that the return type of the method is bull so I'll return true if we successfully created the material and false if not next up is the configure method override this gets called each frame just before applying the effect and we use it to set up any temporary resources required during this Frame it takes in a command buffer and a render text descriptor as parameters the command buffer is a list of instructions for the GPU to carry out and the render texture descriptor describes the size of and sort of information stored in a texture in this case the camera texture inside the method I'll stop immediately if there's no valid blur effect if there is or create a temporary texture with an IED underscore blur text and exactly the same properties as the camera texture lastly we'll call base.configure which runs whatever code the base script will render pass class has in its configure method next up we have the execute method which has nothing to do with capital punishment this is the core bit of the code across R3 classes this method runs once per frame and we use it to set up Shader properties and apply the Shader to the camera texture it takes a script double render context and a rendering data as parameters the script double render context is a conduit for passing our instructions to the renderer and the rendering data that's sort of in the name I guess inside the method I'll check again where we have a valid blur effect then I'll create a command buffer using command bufferpool.get and pass in a profile attack called blur post process this identifier is used by the profiler to track the performance of our code next we need to set up the Shader properties that will be used for are effect our blur settings script dealt with only one property the strength of the effect from this we'll derive two Shader properties if you remember me from earlier for the grid size I found that a grid size of about six times Sigma works thanks me I'll round it up to the next integer value then add 1 if the result is even so that our grid has a central pixel then to set our Shader properties it's a matter of using the set methods on the material there's a set method for each type so for the grid size I'll use set integer but the underscore grid size property and for the spread I'll use set flute with the underscore spread property we haven't written the Shader yet but those are the two property names I'll be using with everything set up we can now run the effects over the screen for that we use a method called Blitz which takes an input texture that we can read color data from a texture that will write to and optionally a material to run over the first texture and also optionally a number representing which paths inside the material Shader to use our Shader will use two passes so we're going to BLT from The Source texture which is the camera texture to our temporary blur texture using a horizontal blur paths which has a pass index of zero then move from the blur texture back to the source texture with a vertical blur pass with an index of one eventually Unity displays that Source texture on screen after all your post-processing effects have been applied these BLT commands get added to our Command buffer and to actually get urp to process those commands we use context dot execute command buffer and pass in the command buffer as an argument after that we can clear the command buffer and then call commandbufflepool.release to clean up the resources related to the command buffer since we're now done with it for this Frame the only method left is frame cleanup which we use to free up any resources were created during the frame it's called at the end of the frame you don't often need to deal with manual memory management like this in unity but be warned that if you don't clean up things like temporary textures after using them you may encounter memory leaks and numeracy will get upset with you the only thing we need to free is the temporary blur tags which we can do with cmd.release temporary RT we need to pass in the textures ID rather than the texture itself then we can call baste or frame cleanup to run the default cleanup code and that's the blur render pass script complete now what tank will be third and final script blur renderer feature this one only needs to import the unityengine.rendering.universal namespace the inherits type this time is script or renderer feature which needs us to overwrite two methods called create and add render passes before we write those add a variable of type Blair render pass to hold our pass the create method deals with creating any passes and other resources your effects requires to work in our case we just need to create one blur render pass but you might end up making complex effects with several passes I'll also change the name variable to blur which sets the default name of the renderer feature when we add it to our renderer features list the and render passes method handles everything to do with inserting passes into the urp rendering Loop it takes a scriptable renderer and a rendering data as parameters these are both types we've seen before this is also where I'm going to call the setup method on blurrender pass because this add renderer passes method gets called before the configure and execute methods on live render paths setup also requires a scriptable renderer as a parameter and we conveniently have one right here if you remember setup returns true if everything got set up successfully and false otherwise so we'll check the result with an if statement and inside the if statement we'll use NQ pass to add blur render paths to our renderer with that all the C sharp scripting is done and we can look at how the Shader works in the unity editor I'll create a resources folder inside my assets folder then create a Shader inside it via create Shader unlit Shader I think all these presets were designed for the built-in pipeline so we'll have to make heavy modifications to it but we need a Shader file to work with I'll name it blur the resources folder is important because usually Shader files are excluded from your game builds unless they're directly referenced within the material or bioscript with a variable of type Shader and that material or script needs to be included somewhere in a scene however we're finding our Shader by its name via the Shaded find method which doesn't count as referencing it so inside the resources folder it goes this Shader foil has a few Key Parts the properties contains all the information we send to the Shader then there's a sub Shader that includes most of the code inside the sub Shader we have a tags list an hlso include book where we write Shader code that gets placed inside every Shader pass and then after the hlsl include block we have the horizontal Shader pass then the vertical Shader pass and that's it here's the basic code we're going to fill in from top to bottom first we have the name of the Shader which is going to be post processing slash blur this is the same name we use in our c-sharp code with shader.find next we have the properties block which contains three properties underscore main text is the input texture that get passed to the material with the blit method and then underscore spread and underscore grid size are the two values we set on the material I'm going to gloss over some of the Shader syntax a bit because I've covered it in previous videos and there's a lot to get through so if you're completely new to shaders I would recommend watching my introduction guide to vertex and fragment shaders then coming back here inside the sub Shader we have the tanks block where I'll set the render type to opaque and the render pipeline to Universal pipeline this should prevent the Shader being used on any other pipeline next up is the hlsl include Port where I'm going to put all the codes that needs to be shared by both my Shader passes that includes importing the core Shader Library file and defining the e-constant which is 2.718 ETC then I'll include all the variables I'm going to use including the textile size of the underscore main text which is basically its resolution all the variables except the texture can go inside the unity per material C buffer which is one of the requirements for the SRP Batcher compatibility then I'll write a function to generate the gaussian curve values essentially I run this equation with the only input being the x-axis value and the shape of the curve being defined by the underscore spread property value next and I'm going to speed through this I'll write app data and V12 struts and the vertex Shader which are all extreme basic and finally we can cap off the hlsla glue plot with an end hlsl after that we can write us two Shader passes we'll start with a pass block which I'll name horizontal we'll open up an hls or program block and use hash pragma statements to instruct Unity to use the word function as the photo Shader and the Frank underscore horizontal function for the fragment Shader now of course we need to write that second function inside the function first Define a color variable which will accumulate the weighted color values from each pixel in the grid and a grid sum value which will accumulate the weights themselves then I'll work out lower and upper bounds for the grid basically how many pixels to the left and right are sample based on the grid size now I'll Loop over all of those pixels and for each pixel I'll work out its gaussian reads by using the gaussian function we wrote add the weights to our grid sum then sample the pixel by adding a small offset to the U vs and multiplying its color by the gaussian wheat then adding the results to the color variable once the loop has finished running I'll divide the color variable by the gridson if you recall the weights might knock quite add up to one so I do this division to avoid getting a color that's slightly too dark finally I'll return the color variable as the Shader output the second pass is almost identical but with a few values swapped out so I'll copy paste the entire thing but changed the name to Vertical change the fragment function name to frag underscore vertical then change all the X values in the loop to Y values crucially I'll change this part the UV calculation so that the sampling pixels vertically and map the Shader complete there's just a bit more work to do before the effect can run in the scene find your Universal renderer asset in a new urp project there should be a few in the settings folder my game uses the one called High Fidelity by default at the bottom click the add render a feature button and find your blur effect this step is very important as it basically enables our effects although right now we don't have any volumes in the scene that can run the effects go ahead and add a volume via game or jet for volume and let's pick books for you there's no volume profile attached to this volume so click the new button and unity will create a volume profile asset somewhere in your assets folder we can add effects directly from this inspector window via the add override button so once again find your blur effect in this menu finally tick the override option next to the front setting and increase it to something above zero then whenever your camera passes through the box volume in either the scene view or the game view your scene should blur my thanks to all my patreon supporters on screen right now you can get access to Premiere Shader packs Early Access to videos and articles or your name in these credits if you could become a supporter today until next time have fun making shaders foreign [Music]
Info
Channel: Daniel Ilett
Views: 8,208
Rating: undefined out of 5
Keywords: unity, unity shader, gaussian blur, unity gaussian blur, urp gaussian blur, unity urp, urp, universal render pipeline, renderer feature, render pass, scriptable render pass, scriptable renderer feature, two-pass blur, two-pass gaussian blur, blur post process, unity post process, post processing, image processing, gaussian blur shader, urp shader, gamedev, game development, game design, tech art, technical art, depth of field, hlsl, shaderlab, fragment shader, vertex shader
Id: AlCuc58z7E8
Channel Id: undefined
Length: 23min 42sec (1422 seconds)
Published: Thu Jun 01 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.