More Toon Outlines! Normal Edge Detection in Unity URP Shader Graph! ✔️ 2020.3 | Game Dev Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi i'm ned and i make games and game development tutorials today i want to power up my edge detection outline shader by adding normal vector edges as well as refining the look for some extreme cases if you haven't already watch the previous video on edge detection outlines so you're up to speed i'll put a link in the corner as well as the video description i created this project using unity 2020.1.17 f1 and universal render pipeline 8.3.1 if you're using a different version check the comments for updates to get started make sure the depth and color detection outlines from the last video are ready to go then create a test scene you'll want a variety of geometry to see how the outlines work on different kinds of objects something smooth something pointy and something with a large flat surface are important to test in the last video we worked with the depth texture and the opaque color texture it's time to incorporate a third the depth normals texture this texture contains the normal vector of each surface captured in a pixel these normals are in view space or relative to the camera as of universal render pipeline 8.3 unity does not provide the depth normal texture for us however we can utilize the old built-in renderers depth normal shader to generate it ourselves a renderer feature can set up and execute a new draw pass re-rendering all opaque objects using that shader and saving the result into a texture let's get started on that in unity create a new renderer feature called depth normals feature and open it rename the renderer past class and its associated instance variable in the feature class and clean up some formatting in the create method call this function to create a temporary material using the depth normals texture shader and pass the material to the renderer pass object visual studio will indicate an error but we'll fix that in a second set the event to after pre passes so the texture is ready when we're rendering opaque objects in add render passes enqueue the render pass in the pass object create an instance variable for the material and add a constructor with a material argument then save that argument to the instance variable now add an instance variable for our list of shader tags unity will use this to search for objects to render any object must use a shader with a path containing at least one of the specified tags an object with a depth only pass writes to the depth texture so it should also write to the depth normal texture next define filtering settings to further refine which objects we render add an instance variable and then initialize it for all opaque objects finally define a render target handle for the destination texture initialize it to underscore depth normals texture which will become a global texture variable that we can access in shaders write a configure function to create the depthnormal's texture and get it ready for rendering be sure to clear it to black since some pixels like those not within a triangle will not be written to normally in execute create a draw settings variable used to describe the draw paths the renderer should execute pass in the shader tags the rendering data provided by the function arguments and the camera's default opaque sort settings we want this draw call to draw the depth normals material instead of an object's regular material force this by setting the override material in the draw settings finally call draw renderers to enqueue the draw calls passing in the call results draw settings and filtering settings override the frame cleanup method to release a temporary texture alright now return to the scene editor and select your urp renderer settings add a depth normals feature to test things out you could create a quick shader graph like this which samples the depth normal's texture make sure that the texture property exposed field is unchecked and that the reference is set correctly to underscore depth normal's texture then create a material with this graph and place it into a blip material feature it looks like all's in order before going forward return things to how they were before you might have noticed that the depth normal texture doesn't store normals directly unity encodes them in a certain way to increase precision i created a decode decodeddepthnormals.hlsl file which takes the decoder code from the built-in renderer and makes it available for our shader graph you can find this file in the video description make sure to place it in the same folder as your edge detection outlines include hlsl file now open edge detection outlines include.hlsl at the top add a hash include line to pull in the decode functions then declare variables for the depth normal texture and its sampler down below add this function to sample the depth normal's texture and decode the returned value into a depth and normal vector it's also useful to write a wrapper function around this function so that the shader graph can access it we want to add one tweak here though before returning the normal vector remap it from 0 to 1 to negative 1 to 1. texture values range from 0 to 1 so the normal vector does as well this remap makes the vector consistent with other normals in the shader graph now let's write a normal sobol function which will run the syllable edge detection algorithm over the depth normals texture there are a couple ways to implement this but i'll use an algorithm similar to color syllable track the convolution matrix sums separately for the x y and z coordinates and then return the maximum syllable value between them all as such normal sobel is basically identical to color syllable except it calls get depth and normal instead of sampling the opaque texture rename variables to be more suitable as well now return to the edge detection outlines graph duplicate the color syllable custom function node click the gear and change the function to normal symbol route the uv and thickness into the inputs of this new custom function node then create a normal strength normals tightening and normal threshold property create another syllable fine tuning node and feed in these new values create another maximum node to take the maximum of the normal syllable and the previous maximum then feed the result into the blend node save the asset and return to unity make sure your outlines material is in the blint material renderer feature and adjust the material settings until things look nice you might notice a couple of strange things first the depth outlines get way too thick when you look down a plane at a shallow angle we can lessen this effect by raising the syllable threshold value when the normal vector is perpendicular to the view direction to do that we need to get the view direction and to do that we need a way to convert from screen space to view space luckily unity's camera has a matrix called the projection matrix which converts from view space to clip space shaders can access it through the variable unity underscore camera projection open edge detection outlines include hlsl let's create a function to take in screen space uv and convert that to a view direction write this view direction from screen uv function taking in a float 2 and outputting a float 3. so unity underscore camera projection variable converts from view to clip space but we need the inverse luckily we can do a little mathematical magic to avoid inverting the entire matrix first grab the first two values on the diagonal these are the values used to scale a 2d vector with the transformation matrix this next line unprojects the screen space uvs back into view space positions by converting to clip space then it divides that with the matrix values to unscale the positions construct a normal vector by adding a negative 1 z component and then normalizing finally since we want the direction to point towards the camera we must flip it we're done with this code so open the outlines graph create a custom function node to call the new view direction function set the mode to file the file to edge detection outlines include hlsl and the function to view direction from screen uv then add a vector2 input and a vector3 output matching the function route the uv into the input and we have our view direction the next step is to get the depth normal vector create another custom function node to call the calculateddepthnormal function in the include.hlsl file set up the inputs and outputs so they match that function and then set the file and function name route the uv into the input now that we have both required vectors feed them into a dot product node this outputs 1 if the vectors are parallel and 0 if they're perpendicular we need the value to be one when perpendicular so use a one minus node to achieve that we only want to adjust the threshold if this value is above a certain number so define an acute start dot property to hold this edge number then set up a smooth step node with this we can interpolate between two different depth thresholds create an acute depth threshold property to contain the threshold to use when the normal is perfectly perpendicular to the view direction then create a lerp node to interpolate between that and the regular depth threshold finally feed that into the syllable fine-tuning node for depth outlines save the asset the thresholds and acute start dot values will take a lot of adjusting in the material turn off all outlines besides depth and try to get things looking right there's still one more strange artifact though notice that when you zoom in and out depth outlines tend to change this is because the depth texture does not store values linearly in order to have more precision for closer objects unity stores depth values logarithmically don't worry this just means we need to lower the threshold for deeper objects back in the graph get the depth using a scene depth node this calls the shader graph sample seam depth function just like we did in depth syllable set it to raw mode feed at the uv and then multiply the output by the depth threshold just after lurping with the acute threshold hook that back with the syllable fine tuning node and then save the asset back in the scene you'll probably need to adjust settings again but things should look a lot more stable now turn back on normal outlines and zoom real far out notice that outlines tend to engulf their meshes this is because depth normals change rapidly per pixel when there are less pixels to represent an object we'll improve this by raising the threshold for objects far from the camera first get the scene depth like we did a second ago but this time set it to eye mode this will give us the depth and world units from the camera's near plane we want two properties to define the near and far depth between which will interpolate the threshold as well as a property to hold the highest threshold at the farthest distance use a smooth step node to step between the near and far depths and then a lerp node to interpolate between the two threshold values finally feed the output into the syllable fine-tuning node for normal vectors save the asset and return to the scene editor these settings will again need some adjusting but getting things just right will really improve the look one more thing before i sign out you might have noticed you can also get the depth value from the depth normals texture it turns out this value is not super useful since it's just too imprecise however if you really need better performance you can convert the graph to use the depth normals texture's depth value this would eliminate the need for a separate depth texture and its paths saving some memory and rendering power well outlines are definitely a tricky thing to get looking right but i'd say that trouble is worth it believe it or not i'm not done with them in future videos i'll explain how to apply edge detection outlines to a single object as well as render super thick outlines with an entirely different technique please subscribe and turn on notifications so you won't miss those videos thanks so much for watching i'd appreciate it if you could leave a like it lets youtube know to recommend this video and it really helps out the channel if you have any questions please don't hesitate to leave a comment how do you plan to use outlines in your project is there any topic you'd like to see me make a video about thanks again for watching and make games you
Info
Channel: Ned Makes Games
Views: 24,240
Rating: undefined out of 5
Keywords: gamedev, game development, development, unity, unity3d, madewithunity, programming, game design, csharp, nedmakesgames, nedmakesgames dev log, indiedev, indie game, dev log, shaders, 3d modeling, blender, tutorial, walkthrough, sobel, outline, outlines, postprocessing, post processing, urp, universal render pipeline, toon, toon shater, outline shader, outlines shader, shader graph, renderer feature, graph, depth normal, depth normals, depth, normals, depth normals texture, depth normal texture
Id: fW-5srSHDMc
Channel Id: undefined
Length: 13min 38sec (818 seconds)
Published: Wed Dec 16 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.