Building a Fancy Stylized Tree Shader in Blender 3.2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everybody it is time for trees well leaves to be specific so a while back i was chatting with some people and they were trying to get some uh non-photorealistic stylized leaf shaders working and i got curious and banged this together and people really liked it that i put it up on twitter and it got like twice as many likes as anything else i've ever posted so the public pressure to do a video about it has been high but this is basically a fast doodle there's a ton of problems with this so i have gone and made a nicer more robust version and of course since it's one of my videos everything is completely over the top and there's a ton of features because let's face it a single tree isn't that interesting but seeing how many features we can pack into something as simple as just leaves that's fun i've taken this as an opportunity to just go through a laundry list of cool stuff that a lot of people probably don't know about so i guess this is kind of a beginner's shader exercise but i think there will be some interesting stuff here even if you have a lot of experience and this is specifically a stylized or npr shading video in fact we only use a single shader for the entire thing and it's not even really a shader it's just vector math there is not a single actual shader node in this entire thing unless you count the transparent shader but i also cover how to do the same exact setup with a regular diffuse node we'll be looking at a ton of different random topics that usually wouldn't go together in any coherent sort of like curriculum but they do go together here because it's a specific project study we're going to be looking at coordinates and radial sphere size normals and leaf normal maps we've got attributes coming from geometry nodes and attributes coming from the mesh with a geometry system we're doing whatever this is we're baking normal maps we've got random stuff per face in eevee thanks to geonodes we've got surface gradients whatever those are we've got fake volumetric density masks we've got the sun angle with drivers to make our shader we've got z based masks occlusion a shader that's not a shader all sorts of crazy color mixing absolutely terrible compile times by the time we get this far into it we've got funky effects on the colors driven by different things and of course at the end alpha texture we won't be going as far as actually doing instancing or scattering in this video but we will be building the shader with that in mind so we'll try to keep it compatible with that whether you're using geometry nodes to scatter or if you're just manually copying things with like all d you can just grab more of these they come everywhere so if you're looking for a video on like how do i quickly get a stylized tree and you know throw them around this is the wrong video for you if you want to learn a bunch of crazy shader stuff and it just happens to be using a tree as a subject then you're in the right place there's a ton in this file i will be tracking it up on gumroad for a couple of bucks and sending it to my patrons so check the links in the description and i think that covers everything so let's get started we're starting from the very beginning we have our tree it's got a very simple diffuse material that's just white we have a default sun and we have a sphere that we'll be using to help test our material the tree is split into two objects we have the trunk and branches which is actually a curves object that has been beveled into having this shape and we have the leaves which is just a huge clump of planes the leaf shape itself will be defined with a texture the setup we'll be covering in this video will work with pretty much any tree as long as it is mostly spherical and has a decent density of leaves it doesn't really matter if they're alpha texture based or if you had an actual leaf model or what type of tree but it does need to be mostly spherical most of what we'll learn would work for other types of trees it just gets more complicated if you have more distinct branches if you don't have a tree of your own to use don't worry it's very easy to make them the sapling tree generator comes bundled with blender so you can just go enable it or there's also lots of other add-ons and geometry nodes setups and all sorts of things there's lots of tutorials out there on how to use sapling it shows up here we'll take only a very quick look because this video is only about leaf shading under the geometry tab you can save a preset once you've made something so here's the tree i have saved the important parts i'm using a spherical shape and then in these other areas most of these settings i haven't touched but i have chosen some splitting sections to have it split higher because i want this to just be a bubble tree same through growth i think i messed with a few things but it's not changing much pruning matters that has defined this curve that defines some of the shape and then it doesn't save leaves being on by default because you can get too many of them also under splitting it didn't save my third level of splitting because again that really ups the performance cost so i probably have too many leaves but we'll talk about that later so that is where my tree came from and i haven't really changed it beyond that i have tracked this material on the trunk and i'm just going to show it to you really quick it's pretty simple and we're not going to be talking about the trunk we're going to stick to leaf shading for this one and that's going to be just hidden most of the video so let's take a look at where we're starting with this shader which is not much of anywhere it's a very simple pure white diffuse no roughness in fact an eevee the roughness slider doesn't even do anything so it wouldn't matter if there was and we have two lights acting at our scene our sun lamp and our world lighting to get good artistic results we need to have full control over our values and colors and understand exactly what goes into them right now we've got a bunch of gray why exactly do we have that well it's a combination of our sun settings and world settings and we don't want a bunch of grey what we want is for it to be black where there's no light up to pure white where it is fully lit and facing the light source so the first thing i'm going to do is pin my material nodes here so that when i click over to other objects with different materials it doesn't change my node tree now i'm going to expand a new shader editor but this one i'm going to set to world to let us get full access to our world settings we can get those on the site here but i'm going to leave that to be our sun settings let's expand that and with our sun lamp selected now we can pin this as well so now i keep access to my sun settings and world and shader regardless of what is selected now let's get these lights sorted out our background aka world aka ambient light is pure white but with a strength of only point one the color is multiplied by the strength so you know one times one is one one times point one is point one also i've got this set to show on the background which is done here otherwise we get a default hdri which we don't want so i'm going to set that to nothing so that we can look at only the sun for the sun lamp we have several settings to worry about what we want is for it to be pure white on angles that are facing the light directly that gives us the best gradient of lighting so what settings do we need for that the color well it's the color then we have the strength higher strength of course is going to get us closer to white and we can kind of see if we look at this that at some point we pass over it where like the white starts like here but it's really hard to eyeball and the angle kind of spreads the shading more around the surface it it's simulating more um ambient light i suppose a light source that's really far away and then we also have all this flickering nonsense the flickering comes from these shadows which we are mostly going to leave disabled for this video because ev's shadows are just kind of crap and you probably don't even want them for something like a stylized tree and if you do well we'll talk about that later for now goodbye shadows and we're going to set our sun angle to zero just to isolate this down to just the settings we need to have a clean light gradient so the question is what light strength makes it so that a face that is pointing right at the sun right at the light source has a value of one and then everything else has a lower value all the way down to unlit faces and what exactly defines an unlit face we'll talk about later and note that another way of phrasing this question is what light strength makes it so that a face pointed directly at the light has a diffuse shading where it is the same color as the lights color you know if this was blue this is now value one blue so pure blue and even though our diffuse shader is white we're seeing pure blue shading i know what strength we need of course but i'm going to show you how to find out first we'll use shader to rgb to change our shader into color data and then we'll get a math node with greater than or less than or something where it is going to give us a mask based on the value going in so it's black where this is not true and it is white where it is true so we can see that this whole area is brighter than value one so we want to adjust our light strength until well until nowhere is brighter than one we just want it equal to one so that's kind of hard to eyeball now isn't it so we could actually use compare instead and set it to compare is it equal to one with a low epsilon this is how much of a margin to allow so now we're seeing that like it's something in here ah we've just passed it we're just below it or just after it and we can kind of like start messing with this number trying to find exactly when this is equal we can even turn down the epsilon even more so at the middle of that we can see that there's a bit that is not within range so that means we're too high and now i guess nothing i guess we're about there huh does this number look familiar to anybody what we've discovered is that the correct strength to have pure white on facing surfaces is actually pi which you can just type pi in and hit enter and it will give you pi to a reasonable amount of decimal points so that is the light strength we want to work with on our sun lamp and check this out i'm going to put my 3d cursor at about the halfway point and we can do pi times two and now we can see that the light strength being doubled has moved the place where we hit pure white to about to halfway in between we can confirm that with our greater than and if we did pi times four now it's three quarters of the way so there's a linear relationship here so the appropriate strength of a sun lamp to give us pure white at the most exposed all the way to black at least or pure whatever our sun color is is strength pi but note this is only the case for sun lamps for point lamps it's totally different because point lamps have fall off based on distance so what strength you need a point lamp to be to get you pure white at any given distance totally depends on the distance of the light from the surface and the falloff settings and radius and all that kind of stuff but we're only working with the sun lab here if you're trying to do some sort of weird like nighttime scene of trees lit with like street lamps with falloff then you're going to need another solution but presumably you're going to light trees with the sun and really for most npr shading in the eevee you're going to need to work on the sun lamp because you just don't have very good controls with the others so that's the color and strength balance now what about angle what is this doing as we turn this up it's actually lighting further around the sphere it's lighting faces that are pointed away from the light source and this is kind of simulating if instead of this just being parallel rays if there's a bunch more maybe like ambience or bounce light you know it's simulating a sky where light is actually coming from a lot of directions now this can be a bit weird because if shadows were enabled this would actually be shadowing itself from the main light source but we're not really going to worry about that right now so we'll talk about this more in a bit but for now we're going to leave it at zero now that we've got a very basic shader working our next problem is that our leaves are just a total mess because it's just a bunch of planes from some angles they look okay from other angles they're just black and this is because of a bunch of issues but mostly it's that the geometry is very simple and the normals are not doing anything interesting we've got a mix of front faces and back faces in there we take a look at the normal from the geometry node it's just a mess all around and on our sphere it's fairly clean but then here we've got some stuff that's up some stuff that's down and it's just no good and if we go down to our back facing we can see that on some of these we're looking at the front face and some of the back face we are using auto smooth and we are on shade smooth but that doesn't really do anything when you just have flat planes since this is a stylized tree we are going to use spherical normals we're going to make the whole tree shade exactly like a sphere which is part of why we have this comparison i already have a normal edit modifier set up we'll turn that on and now when we render and look at the normals it's looking a lot better we can kind of see the same sphere shape that's hard to say but there's other problems going on normal edit projects the normals uh from a empty object so we've got that here we don't really need any special settings on the normal edit modifier it just copy this is just the default settings with this empty selected and i positioned it in about middle of tree so if you're familiar with normals and if you're not you should go get familiar before continuing you'll recall that these colors are telling us which direction a face is pointing red indicates how much it's pointing on the positive x minus one on red which would is black it would be minus one and x and green is y axis in the positive direction blue is z but we're seeing a lot of green on this side where it should be negative like the program thinks this face over here is facing that direction which is not correct we are getting this because of back facing problems and that is because on a mesh level the concept of the back face doesn't really exist that's a shader concept and we're setting our normals on the match level so if we look at like a simple plane in edit mode with normals on we can see here's where the normal is facing and the normal of the back face is just the opposite it's the inverse of the normal of the front it's p it's going to be pointing this way by default so when we do custom normals on a match level it overrides the front face and then the back face gets the default behavior of just being the opposite of that but that isn't good behavior here because we're trying to have this be a sphere and because our normals on these planes that were generated by sapling are just pointing in all sorts of random directions the solution isn't very hard because we do have access to the back facing we just need to invert the normal on the back facing that way it will actually be pointing in the same direction on both sides of the plane in order to invert the normal it's pretty simple we'll get ourselves a color mix and set it on multiply and set the back facing to be the factor so where does it back facing it gets this multiply and we will multiply it by minus one that inverts the normal and now when we turn that on everything looks dandy it matches our sphere quite well i've cleaned that up and now we'll plug it into our shader and we have proper spherical shading if we move our sun around we're getting the same shading on our tree as we are on our sphere which was the whole idea so there are some downsides to this method our normals are dependent on the object location its scale and rotation don't actually matter but it does mean for every tree we need to have this object so if we want to make lots of copies like instanced copies of this tree then we also need a copy of the object for every one of them and the other downside is we lose access to the base normals which does matter for texturing like if we want to use a leaf texture for a normal map or something like that it doesn't matter for uvs that does for normal mapping so we'll be coming back to this later as well and looking at other options now that the shading doesn't look quite as terrible we can talk about the world lighting for now i've set the sun lamp to 90 degrees on x and z which is pure horizontal lighting as that makes it easy to see what we're doing so the world light how exactly does it work how does it interact with everything else it is actually very simple whatever we're getting out of this is added to our shader so here is a light strength of 0.3 because 1 times 0.3 is 0.3 and this is exactly the same as doing this that and that are identical and actually since we've done a shader to rgb it's also identical just adding with a color node or even using a math node it's all the same thing and since that is identical we can even do this instead we can subtract and completely cancel out our world light we can still see it in the background so that goes up to five this will need to go up to five and this holds true even if there's color involved like let's set that to be full blue and now we will subtract 0.5 times blue from it and we are back to our black to white so using the world light at all is exactly the same as adding that to everything in your scene and you have no way to control or stop it because this is just built into the diffuse shader we don't have a way to tell the shader to not be affected by the world light we could cancel it out like this after but that's a bunch of extra work and extra compile time and processing and you can also cancel out the sun lamp as well by dividing by the sun uh color times normalized strength uh we won't get into that because you just shouldn't do that there is a better option and that better option is the light path node this is a node that does a lot more in cycles than it does in eevee because in cycles there's all sorts of light bounces and tracking light but it still does some things mostly these top outputs is camera array gives us a mask of if something is directly visible to the camera which is another way of saying a mask between direct and indirect so if we mix between two things based on this then the one in the second socket is the one we actually see visually and the other one is what's used for indirect things like light so this lets us say have the light cast by the world to be a different color than the light visible on the world or more importantly it lets us set a zero and just turn it off completely so this is the sort of setup we use if we want to be able to control our background color or like put a texture back there or something but not have it affect our shaders at all now again this isn't something we can control on a per material level that's just a limitation of eevee in other engines like malt we can but this is just how it is for now you could of course delete the world entirely over here and that's the same as you're choosing black so we're not going to go quite that far so here's a handy note group i use which is just this is camera ray mixing between different color and strength into one background shader this isn't really different than mixing between two background shaders it doesn't really matter this just happens to be how i set this up so this just makes it quick and easy to choose what are visible and direct and indirect settings are now why is it so important not to have the world color interfering with our shader i'll give a quick and easy example which is if we wanted to do something like a tune shader generally a tune shader is done with a color ramp like this and you do some amount of ramping to squish your shading into a narrower band of some sort and this is based on the input black and white so as soon as you use any amount of indirect light you're changing what your original gradient values were which means you're going to be changing your toon shader relatively and that can get really weird depending on what your light is because like colored light is effectively weaker because rgb111 equals value one which is what's going to be used here effectively whereas if you have less than that it's the same as lowering the value so what this means is that as you use the same asset in different lightings and different scenes it doesn't change how bright the lit area is but it changes the size of it and it can change them in really wacky ways so it just doesn't work you need a consistent normalized black and white shading gradient if you want to do a ramped tune shader now we're not planning on using toon shading for this tree you could but i'm not going to because it doesn't need to be that complicated but we are going to be using our shading mask for various things here is a quick example we want to have different colors in the lit areas versus the shadows so i'm going to pick a green here this can be our main tree color and then where it's going into the shadows we're going to have it get a bit blue and then we need to get our shading back which means multiplying that by the shading color and now in the most lit areas we have our trees green and then it shifts towards blue in the shadows coloring shadows like this or doing hue or saturation mixes is a really common part of stylized art so we want the capability to do this and again once we start doing this it's going to change it and maybe that doesn't matter maybe you want that but if you want it to be consistent then we have to have that normalized shading mask all right but what if you do want world light still well it's not too hard to just do it in the material and ignore the usual world settings so here i have a node group in the world nodes and i'm going to connect all of these up and all that's happening in this global values group is that i can set all of these parameters in the same place and that means i can copy that and put this node group in my shader as well and we did already mention the math involved here it is color times strength and then it is just a matter of adding that in before we multiply by our actual material color and i'm going to disconnect it here and leave these at nothing and now whatever i set in here it's exactly the same as using the world but only for the materials i've set this up in so that is how we easily get material level control over world color and strength but there are other aspects of using the world that might not be so simple like if you want to have it affect glossy reflections or more complicated stuff it can get quite complicated if you want that to be global because the world maps things in a certain way and then you have to map those onto the objects the same way because this is material level and it's a whole hassle so usually when doing npr you're already not using the world but if you want to use a tree like this or like use the shader in some scene where you're doing like stylized pbr or something that does use it then you need to be aware of these issues for now i'm going to move forward assuming that it's only going to be our own material level world or ambient lighting which means for now this is going away but we are going to come back to some of these options later let's return to the sun angle setting what exactly does it do and do we want to use it the default behavior at zero is that faces facing the light are fully lit with value of one and then it's a gradient down to perpendicular faces which have a value of zero they're not lit and everything beyond that that's facing away is also zero as we turn it up we can see that more faces are getting illuminated even ones pointing away from the light but the strength of the illumination is lower in fact it has halved and an easy way to check that is we can use our world settings and set the background to 0.5 and now it's easy to see 0.5 on the background 0.5 on the sphere so that's just a quick way to compare values so our light is broader but weaker if we wanted it to still go all the way to one we can multiply the strength by two and now it does or if we were leaving the strength at the same amount we could do the multiplication in the shader with a map node and there we go this would matter if we had other things in the scene that were using the same sunlight and we wanted i guess different values although generally you shouldn't have a situation like that okay so do we even want this effect should we be able to have our sunlight light up things that face away from it well normally i would say no but we are doing non-photorealism and that means anything goes if it matches style but even within the realm of a fairly realistic style in this use case of the tree i do want this effect and the reason i want that is because we are doing a stylization of a complex object that light can actually pass through you know in a real tree light doesn't just end halfway through so it can pass through the leaves and branches it doesn't occlude like a hard sphere and if you were drawing a tree you also wouldn't have it be so you know severe light doesn't just stop halfway across it so this is a way to let us kind of get a visual style that implies more light passing through without doing anything very complicated so it's a subjective stylistic choice but i think it's a good one in this case so even if we have the angle at 180 we can still use a map range to choose where we want our terminator to be we can change it back to the old behavior or have it only be 0.4.3 this is kind of like a tune shader now so if we knew we wanted this option available to everything in our scene then we just set our strength to pi times 2 and set the angle to 180 we don't need this multiply and then in all of our shaders we use a map range to choose how much of this we want so it's effectively material based angle but if this tree is going to share a scene or lights or anything with any other sorts of materials or like pbr stuff or anything where this is a problem and you don't want to put it like its own layer or scene or something it would be nice to just have this be completely independent of the sun so we're going to look at a bunch more options to get diffuse shading let's understand how our diffuse shading works in the first place but down here i've got our normals again and i've got a dot product node and well that looks like diffuse shading doesn't it what's going on here and this has nothing to do with our actual light this is pure math we are calculating something based off the normals and the direction from this vector input and we can change that to something else now it's a light facing down and that's because what shading is is a calculation comparing normal angle to light angle and then color and strength multiplies that this dot product calculation is actually part of our diffuse node it's a key part of all shading i think and what it is is a comparison of two directions one direction is our normal which is a different value in different places on the model so you know on this side of the sphere it's mostly one x and you know over here it's one y and then it's a mix between along the curve of the sphere and our dot product angle here is just one on x which is this direction down the x-axis so the dot product compares these two angles if they are pointing in the same direction like this part of the sphere is pointing on x-axis then you get one if they are 90 degrees to each other you get zero and if they are negative angles you're actually getting negative values all the way to negative one we cannot do this for our regular diffuse node because it doesn't have the values below zero it's been clamped at some point which is the same thing as if we threw a clamp node in here clamp eliminates all values below zero everything below zero becomes zero and everything above one becomes one so we cannot stop the diffuse node from clamping because we don't have access to its internal workings if we did we would just do that and we could you know get around a lot of these problems so the reason we have to do this sort of like light faking and all this stuff is just because evie is hard-coded into certain options whereas in malt we would be able to just make a custom version of our diffuse shader that expose these options so just creating our shading out of vector math has a lot of upsides we get more data from it and we're completely disconnected from the regular light and world systems and all that stuff so they can't mess it up it's really handy for stylized shading but there are downsides we cannot get cast shadows at all but we probably don't want them on this tweet anyway so it's not really that much of a downside and evie shadows are awful so they're basically unusable in my opinion so whatever but it might become a problem if the shadows ever get fixed so the other downside is that we need to build our own controls for these lights we can still sync them up to some object including this same sunlight so let's do that next we're going to need to get the current rotation of the sun lamp and we can do this with drivers we can copy his new driver and paste these onto a combine xyz this may look a bit odd because i i'm copying 90 degrees but when i paste it's showing 1.571 but that's because what it's showing here is radians instead of degrees all rotation math in blender is actually done in radians it just converts to or from degrees for the user interface to make it a bit more human readable so we've got the sun rotations now but we cannot just plug that straight in this is giving us 45 degrees down from the right and as we adjust the sun it's always going to be a bit off unless we go to zero but wait zero is nothing taking place at all the problem is that these rotations are not the angle of the sun their rotations on top of its starting position to get to the new angle so it starts facing down on z which would be minus one z and then minus one z rotated by these amounts is the sun vector let's get a rotation node so minus one z that's the original vector then we will rotate that by we're gonna need euler and we won't need the center so we'll just okay now that is moving correctly but it is inverted the reason it's inverted is remember dot product returns one when the vectors are in the same direction and right now the sun is pointing this way and you know these surfaces are pointing that way so they're pointing at each other not in the same direction so we're actually going to invert the starting position and now it works correctly even if we return the sun to zero so that's the sun lamp working but remember this could be done with any object an empty something else doesn't have to be the sun lamp and it doesn't even have to be a lamp or an object at all the normal node lets us just get a direction vector and we can rotate this sphere in the node itself and control the light angle that way now this is a bit counter-intuitive because the default is this assumes you're looking straight down on it so we're looking at you know white of the sphere but it's actually shading on the bottom but we can correct that by rotating it 90 degrees on x and now it's going to match up with what we see and the second one is uh input only used for dot so we can actually type that another neat feature of the normal node is that we can do this in a group and use it to create that normal sphere as a group input that's plugged into this other socket so we just don't need this node anymore now but if we don't have that node we do need to add a vector math normalize in order for the rotate to work properly so if you wanted to have a big node group for this tree in the end and just control the light angle completely in the node settings you could do it with this and of course you can just define the angle with a vector input if you're familiar with how to do these this is one on x that's facing up on z you know facing down on z etc so you have a ton of options you can really do it however you want i'm going to stick to the sun the driven value for now but to make it a bit more convenient i'm going to bring back the global values group and i'm going to copy this node and stick it in here and that deletes the drivers so that's a hassle i don't want to have to recreate them but there is a trick to get around that which is you add the node to a group and then we copy the group in here and then we disband the group and now we do have our drivers so that's how you copy a node with drivers i guess that should be sun rotation not angle technically and i've trucked it in a node group and named it lambert shading because that's the name for this next let's make it so we can control the angle so we start with our original shading with the terminator in the center and it goes all the way up to one if we add to it now things are too bright but it goes all the way so we multiply it by point five to make it zero to one again but if you recall the actual sunlight angle when we turn it all the 180 is 0 to 0.5 so if we only multiplied it by 0.25 we would have that but you know we don't really want that for anything so we'll leave that at 0.5 now we want some sort of mix for the angle so we could just use a mixed node between this and this but what if we wanted our terminator to be more in this direction this won't let us do that our next option is the map range node right now it's not doing anything because our input is zero to one but we can tell it to treat it as if it was 0.5 now it's in the middle or we can go all the way up here so that gives us a good range this is basically the control we want and actually if we're using the map range node we could just bypass this other math entirely and tell it minus one to one because that's effectively what our original input is there is data in this black here it's just below one and if you remember the map range node lets us basically tell it what the input range is and maps add to an output range that's doing a bunch of math to do that so this does let us do the right thing but what i'm looking for here is to have a node group input that goes from 0 to 1 with 0 being over here i don't want it to be minus one to one so we will keep our add and multiply so the map range node is solving our problem and i could just make a group input of from min but we're not using a lot of the features of the node so let's just actually make this out of pure math so that we can understand what's going on here so our goal is to have it so that when an input number is at zero things look the way they are and when it's at one we have scrubbed the gradient all the way to the right i guess actually everything would turn black when the input is one which is what it was doing on the map range node we've already adjusted the range with add and multiply so we're going to need to do further addition or multiplication based off some input so we know that adding effectively moves the terminator the point at which everything is black to the left if this is -1 1 then as we add to it we are remapping this to be zero to now two that's why we need the multiply to bring it back into the range of one so to move it back again we would use subtraction or negative addition i guess it's worth noting that this multiplies by a decimal value so technically this is division so if we subtract one then well actually that did the job let's make our input there we subtract zero nothing happens as we step this up we can see our terminator moving so that's actually pretty easy once you've subtracted 0.5 we're back to where we started but this isn't going to one anymore we're now 0.5 to 0.5 well we're 0 to 0.5 so we need some multiplication to restore the top end to being 1. we multiply by 2 then that is correct so when we're subtracting 0.5 we want to multiply by 2. so how about if we're subtracting more like let's do 0.75 and now we need to be multiplying by 4 in order to have it be the right amount so to complete this we need some relationship between point seven five and four so what's the math where when a value is point five we get two when it's 0.75 we get four it would be this we subtract our value from 1 which is inverting it so now this would be 0.25 and then we divide 1 by that amount so 1 divided by 0.25 is 4. or if this was 0.5 it would be 0.5 1 divided by 0.5 is 2. and now we have the desired behavior where as we step up from 1 we get a full gradient across so our brightest point is always white and our darkest point is always black and never below and we control where the terminator is and that is what is going on inside of the map range node by the way if you look up the map there so now we will make this a group input and we will set that to default to 0.5 with a min of what zero and a max of one and we will call it terminator maybe terminator position and now we can scrub that now this control we've made is zero to one and that is different from the sun angle which is 0 to 180 and actually 180 on the sun angle is our zero so if we did want this to take a angle input and work exactly like the sun then we would remap this if you wanted that behavior instead you do math like this we're taking an angle of 180 we're dividing it by 180 so when the input angle is 180 then we'll have one we invert that and then we multiply it by 0.5 so now when we scrub this 0 is 0.5 on our gradient and then 180 is our zero in our previous one or one or whatever anyway it's the same behavior as the sun and we could even keep going and remove our multiply that is putting this to one and have this be zero to 0.5 like the actual sunlight and we could add a strength value and make it so that you know uh a strength of pi is equals uh value of one and higher than pi multiplies it and lower than pi multiple divides it but multiplies it by less than one you could completely recreate the exact behavior of the sun line if you wanted to but all of that is just adding extra nodes that we don't really need so that's why i just choose to directly pick the terminator position as a value between 0 and 1. and now i have cleaned that group up and given it some labeling and i'm outputting both the full range and our shading mask after we've chosen our terminator positions we might want both since we're on the subject of faking shading it's a good time to mention another thing that comes up a lot in npr rendering turn on the ground plane i've got here which is just a diffuse shader and it's not really getting any light right now because the sun lamp is not angled down so often we have a situation where we want to have something like a tree cast shadows on the ground but not receive them themselves and currently if i turn shadows on we're getting that so this is just another benefit of using this method we still have to set our shadow mode to opaque or i'll flip or something doesn't really matter right now but we'll have to think about that when we start adding transparency for our leaves but yeah so this is just a perk of using fake shading before we move on from shading we'll look at one more example because i'm sure somebody out there is going to want to fake their sun angle and control it in the material but not want to use entirely fake shading so is there a way to do that with diffuse shaders still and the answer is this so we have a regular diffuse shader black white cut off at the usual spot then we have a second diffuse shader but all the normals have been multiplied by -1 this inverts them so now it's lighting in the opposite direction from the light that gives us shading information below the usual cutoff point we can then remap that into something we can use we've flipped it from zero to one to point five to zero so now we have black to 0.5 ending here and then on our first one we're flipping it uh to be 0.5 well 0 to 0.5 then if we add that together we get the full 0 to 1. so that gives us the same thing we've been working with in our lambert shader and we could then add the same like remapping and terminator position and all that but of course since we're back to using actual diffuse shaders this is now subject to light color and strength and world lighting and if we try to use this with shadows it's a total mess because it's going to self shadow and that's going to mess up all of that so i'm going to stick to the fake lambert shading let's get back to our color mix setup so before we were mixing between our two colors based on the shading and now we can do that and we can move the terminator position so in this setup areas that are darker are more blue and areas that are lighter are more green and we're moving where those areas are but what if we wanted it to always be blue in this side rather than blue wherever it happens to be dark now that's where we can use the original shading gradient to get a different mix so now as we move with the position we're revealing more of the blue now is this an effect you actually want that's up to you that's a subjective artistic choice you can make and we don't have to have it just be the original gradient we could say choose different terminator positions for the shading mask and for the color mix now i do like this effect and you'll start to see why as we keep building this up so we're bringing in some fake indirect light now and we're adding it only into the shading mask and it doesn't look quite right because we need to go back into this group and clamp that and while we're here let's clap that for safety so now we don't have anything going to full black because we're adding light and that means we are revealing that color gradient in the shadow areas as well so that's the reason you might want to have it this is still moving our lick gradient and at this point i think it's time to chuck this all into its own group for better organization to save some time i've just gone ahead and set up the group and now i will tell you about it first of all i have removed the terminator position control from the lambert shading because i want to have two of them so i'm going to do it in this new combine colors group this looks like a bunch of stuff but it's just the things we've been working with so first of all we get our shading gradient and the terminator position just like before and we control that we have ambient light color and strength like we learned about earlier for the world group it's light time strength this doesn't really need to be clamped they add together that gives us our shading mask and then down here we are picking a different terminator which is the same input but multiplied to be two-thirds of that and then that's the mix between our colors and we multiply the shading by the colors so now as we adjust our terminator position we're always going to have a bit of a blend between our shading color and our full color unless we disable ambient strength entirely we've still got a little bit but we're not seeing the full thing but for a tree you're always going to have like 0.1 maybe 0.2 amp in light higher than that probably not but yeah that's a pretty safe bet even for like a nighttime shot usually instead of letting things go full black you would just tint them even more blue or something like that but again artistic choices speaking of ambient light strength it can go higher if we're using a color other than white which you might be if you're trying to you know like tint the shading something for whatever reason you know for um a different day or for some atmospheric effect but keep in mind that as you go to the edge of the color wheel you're reducing some of these values to zero so it actually gets darker like near the center it's bright and now by the time we get to pure red it's really dark in fact the ambient light isn't doing anything right now the reason for that is the way the color math works so here we've got our ambient light which is red red has essentially replaced black in our shading mask as we've added red to it so in areas that were already white white already contains red so those values are probably above one but in areas of the original mask that were black there's nothing there but the red that's been added so in our light pass everywhere is at least value of one on red and then some areas also have blue and green totaling up to one then in our color mix we only have blue and green red does not exist in our color so the problem is we then multiply them and if you remember how color math works it is each component of this does the mathematical operation on the corresponding component here so in this case we have the red here is being multiplied by the red channel here which is zero so anything multiplied by zero equals zero and then up here we do have some green and blue multiplied by green and blue but our red is completely cancelled out because there is no red in the color make if we come in here and we add even a little bit of red in then suddenly it appears because there is something to multiply it's not just killing it so this is something you need to keep in mind when choosing your colors now we could use a different math setup and like mix shadowed areas to the ambient color instead of multiplying them that could get you around this problem i'm not going to do that in this case but if you really want to have it super boosted ambient colors that is an option moving on we also have to watch out for what color we choose in the shading color like if we choose something darker it can totally ruin our value balance or if we go to like saturate or something things can get weird mostly it's a matter of value so let's put something in to keep that from going crazy the goal of our shading color is to tint the main color of the tree towards something else in the shaded areas not to totally take over and clobber it and there's lots of ways we can set this up right now we're using a straight mix to another color but we could also do something like a hue shift with hsv the hsv node makes relative changes to your colors so right now nothing has happened even though i've put in a factor nothing happens until i change one of these values so if we change value it's gonna get brighter and we can see it's gotten a bit brighter there it was already really bright so this is multiplying the current value when it said one that's multiplied by one or we can turn it down and go all the way to zero then saturation is boosting or reducing the saturation lower saturation tends to look lighter it's going more gray and then hue is going to move the hue from wherever it started if you're not so familiar with these concepts here's how you can see it on the color wheel when we have no hue and saturation we only have value to work with value is its own slider but what hue is doing is as you move hue it's moving you around the outside of the wheel with zero is red and then also one is back to red so if you start with a hue let's say here and then you're adding or subtracting from it then you're just getting whatever is to the right or the left of it on the color wheel and the saturation slider is moving towards the center of the color wheel which brings you towards white or it brings you towards just being whatever the value is so we could just have our color shift be hsv uh we do need to invert this because otherwise it's changing the lit area and we want to change in the shadow area so if we did this here is our same shift to blue in the shaded area the problem is if you want to use this setup where your input isn't necessarily going to be green in the case of this tree well trees pretty much only come in like green although you know a bit towards towards yellow unless it's autumn and then you might want to say like orange or red leaves so do you want those to shift to blue maybe not maybe yes do you want them to shift to green right now our hs viewers are shifting this way around whichever whatever we input is shifting count uh clockwise i guess that is so if we want it instead to always shift towards a the same place then the hsv node is not the right tool for us so we could do something like this we can separate hsv and get those values isolated and then recombine them and that means we could do some mixing in between like say mix our hue to always be towards 0.5 which is right between blue and green and or we can go uh lower let's see higher looks like it's clockwise so there's the hue for a light blue so now with a setup like this no matter where we start it's always mixing towards blue which can get pretty crazy so you know i'm not sure you do want this but that is a different way of doing this mathematically and of course if we do want to pick it with a color wheel we can just have it mixing towards the hue from our other color so now it's only using the hue from here it's completely ignoring the saturation and the value so that's probably i think that's about the behavior i want but there is a better way to do this without all the separating the mix node already has the option we need and it is called hue what this does is you choose a color in input 0 and then that color will get mixed based on the factor which is our shading towards only the hue from input 2. so we see as we move the hue around it is mixing to that hue but the saturation and the value do nothing unless the value gets so low that it makes the hue not do anything you know because it is multiplied by the value so this is perfect if we want to use only the hue from our second color except we need that the other way around so again we would need to invert the mask there we go now that is working we also have the same options for value saturation and color color is saturation and hue at the same time but not value like if we want to change that to color now when we address this our saturation does work and our hue works but the value does nothing so i think that's actually the one i do want to use but again this is completely subjective up to you this is the actual making artistic choices part of all this so there we go that is our color mix setting all done and now i will we get a bit more ambient light and we shall continue our next topic is the glossy shader that's another usual part of any shader setup so it uh well highlights where the light is hitting more gloss is different from diffuse because the brightest area has to do with where the light is hitting but also it's dependent on camera so notice now the brightest part is you know there basically the hot spot of gloss has its size determined by the roughness the size and strength but the location is like halfway between where you would expect it to be brightest infused shading and the gradient of the normal on camera position so we could make a completely math-based version of the glossy shader as well but we're not going to and we're not really going to talk about gloss because it's just not really necessary for a tree artistically i do want some sort of effect like this that changes things based on more light we've got a bit of that here but this is all a bit too linear so i would like to brighten it or something but it's not really necessary to use gloss for it since the tree you know isn't shiny like leaves are shiny but the whole tree shouldn't have a hot spot so if i did use gloss it would be very rough and then when it's this rough well i've already got a shading gradient i might as well just ramp that again or whatever so that's what we're going to do my alternative is that i am going to use a hsv node to do an effect we're also using a map range node this time because we are doing something a bit more complicated so this is a very subtle effect that's not easy to see here but i'll turn it up more what this is doing is in areas where the incoming mask is zero we are setting the saturation to two so that is making it more saturated in the dark areas and the areas where the incoming mask is closer to one it is desaturating it so i'm not quite sure how much of this i want but you can see that and since saturation is tends to lighten things because you're kind of mixing back towards uh the value then it is give me the net effect of lightning things a bit based on how much incoming light there is now you can see that more i think that's a bit too strong now the impact of this really depends on what colors you're putting into it and that is because again the hsv node is relative so if you start with a very desaturated color like you know there's like hardly any saturation here then there's not a whole lot of a difference on that part of it whereas if you're starting with a color that is super saturated then you're going to notice it a lot more so we could instead use a mix more like this but i think this will be fine for now i haven't gotten into any trouble with it yet i think i'll go with 1.5 and 0.9 so it is definitely a subtle effect but it's just enough to break up the linearity a bit goodbye gloss node if anybody is really curious about doing fake shading with gloss then feel free to message me but if you're getting so much into shader math that you're interested in that kind of thing just go use malt that is my advice all right so what comes next i think i'm pretty happy with our shading options and our color options and now we have a couple of obvious flaws one is that everything is still just squares so we do leaf texture and the other is that the whole shape of this is still a bit dull if we zoom out enough this actually works okay even with no leaf texture like if this was gonna be on a bunch of hills way in the background of like a landscape shot then we may not need much more than this we may not even need this you could probably just do a flat color mix and you know whatever but yeah i guess we can do a leaf texture next i've got it in its own group and let's hook that up and now we have leaf alpha nice this is getting interesting and at this point i'm also going to hide our trunk because it doesn't really have anything to do with anything we'll bring that back at the very end inside this group we've got a few things going on we have the actual leaf texture which looks like that or perhaps this would be a good time to get the image editor oh sneak peek there actually we have four different leaf textures they are slightly different and what we have going on here is that we are picking a random one off that sheet of four so that we have some variety and we're doing that based on a random attribute coming from geometry nodes that's over here i turn that off then they're all set to the same one and then we have the actual mix based on this leaf texture it's not using the alpha because this is just a black and white texture so there's no reason to put it in the alpha channel so that is mixing with our shader and transparent for that to work transparent alpha clip needs to be enabled for the blend mode and for it to affect shadows it needs to be alpha clip on shadows we looked at shadows earlier and then over here we are exempting our test sphere because i don't want it to get the leaf texture on it otherwise we have that the way that's done is in the object relations of the sphere i've set it to have an object pass index of one whereas the leaves have zero so the object info node is bringing that in so now we can see zero and one and we're mixing to just have the shader and not have that transparency because we want our sphere to keep working as a proper uh material preview and with the leaf texture on it it's a bit difficult so where did this leaf texture come from how do you make one for yourself well i modeled it in its own file this is pretty straightforward i modeled one set of leaves here and then i duplicated that four times i have some displacement on there and i use proportional editing to give them very slightly different shapes you know just to bend them different ways it i'd like to have some more variety and it's not a very good leaf but it's good enough for this tutorial and then we have a camera which is set to orthographic the scale is one because i've got this reference bounds object which is one by one each of these leaves is you know within that then we've got a black background and you just hit f12 to render it and there is your leaf texture and then you just save that out so that part is very easy and there's all sorts of stuff you could do to generate procedural leaf textures i only did four different ones you could have a lot more than that and i guess these are leaves kind of like a bunch of them on a twig i thought that was appropriate for this tree if that is or not for you depends on how you make your tree the next is our randomized uv tile which is more complicated we want each leaf to get a random fourth of that texture and there could be a lot more than four but you know that was enough to demonstrate this so we have a uv map of the leaves which was generated by sapling and we have a random value per island coming from geometry node now ideally we just use random per island from the geometry node but we go down to that it doesn't do anything because it is not supported in eevee that only works in cycles we have to use geometry nodes for this but that's not a big deal at all and we'll look at how that works in a minute for the randomized uv tile group we're going to take a quick look through it but we won't spend too much time on it because i already have a whole video about how to do this here's the article on my blog there's the video i'll put the link in the description that explains how the whole thing works and with a more complicated setup than i'm using here although i think in that one i didn't account for random per island not working in eevee the use case in that video was based on every different piece being a different object so it doesn't matter now though because we have geometry nodes so let's take a quick look the core of the group is the get uv tile group which is covered in that video this lets us split our uv map into columns and rows and pick which one we want and then we feed random numbers into that based off our random per island and based off random per object in case this was being done on an object level or for when we duplicate and instance the tree so there's our random per leaf and here is a random value for the whole object if we duplicate this that has a different one we combine them in this case there's a lot of ways to combine different random seeds in this case i'm adding them together and then using a wrap what wrap does with these settings is it makes it so when you go over one it wraps back to zero so a value of 1.1 inputted would give you 0.1 so this way our random value always stays between zero and one that's not the only way to achieve that i just thought it was cool and that i would tell you about the wrap feature so then we've got all this other math and what this is doing is taking that random value between zero and one and making it a random value well making it four one two three or four or it might be zero one two or three anyway it's doing some comparing and addition and this is all also covered in that other video because it needs to be formatted into columns and rows in a 2x2 grid so once all that is done then we do end up with a random one off that texture it would have been easier i guess if i had to be four in a row instead of two by two you know whatever i already had this setup made so i just used it and the point of using a group like this is that this can scale to any amount of rows and columns we want so if you are interested in setting up a randomized texture go watch that other video for now we will move on here is the random per island geometry nodes group it's pretty simple but there is a bit to explain here so the random value node it gives us a random value between two numbers we can choose what type of thing it gives us and what we need to pay attention to is the id and the seat we want to make sure there isn't any id being used or something like this and the seed i have plugged into the group input so that you can change it here this way you can choose the pattern of your randomness so seed is what you feed into the random generator as long as you have the same input seed you'll always get the same outcome so the question is how do we have this be random per face instead of per vertex or edge or whatever the random value node doesn't control that at all what controls that is whatever node is calling it if you've watched my other videos on geometry nodes you'll be familiar with this but basically you follow the geometry to see the order of execution of the tree so our geometry comes in it hits the store named attribute node and that is looking for a base attribute and so when it gets to this node then it gets the random value for whatever domain is in use on this node so if i change it to point it's now random per vertex if i change it to you know well edge you're not really going to see much because it's going to interpolate it back but basically it is what we choose here that defines if it's face or vertex and here we set the name of an attribute to save this all to now i've named it rndm face and this will create the attribute even if it doesn't exist on the mesh like in the attribute section nothing exists is being made by the geonose group we don't have to assign an output we could output this instead and do it that way but the store named attribute node takes care of our face selection as well so this is all we need and then we use an attribute node here if you have attributes on a mesh they will show up here but since this is being made by geonodes we have to use the attribute node and manually enter the name here that i've just in the rest of the node so that's it that's all you need to get random attributes per face in eevee okay it's time for the next rabbit hole i'm pretty happy with how this is progressing but it is a bit bland it's fine to shade the tree like it's a sphere but if it's too clean of a sphere it's just well it's a bit bland i'm gonna get some more shape into that because you know we've got lumps and branches and all that stuff i'm going to show a bunch of different ways to improve the detail level but before we get into them we have to first deal with the way we're defining the shape of the tree because they're going to be based on it and by that i mean the normals our current method of getting our spherical or radial normals with the normal edit modifier and an empty object works fine but it has some limitations and it gets in the way of other methods and it doesn't duplicate that well i do want this whole tree to work when being instanced so we're going to get into how these radial normals work and how they're made and our other options for making them that will behave a bit better and the first step is to understand exactly what behavior we're getting right now so currently our normals are being projected from the point the empty is at so its location matters but its rotation does not its scale though does matter if we scale everything there's no difference but if we scale only one or two axes it's going to be like squishing this that's pretty easy to see up here we scale that down or if we scale the tree object notice it's changing a bit too if we rotate the tree object then we move it away if we rotate them together then i'm going to do that around the 3d cursor then it works fine we can see that we still have z is up because remember this like sort of cross we can see is our axes it should be staying consistent even as the mass moved and if we rotate it on z the normals stay pointed in the right direction in world space and that's important because if you were duplicating this tree and instancing it one of the ways you would stop people from noticing that you're just reusing the same tree asset is by having like randomized rotation and one of the problems that i mentioned earlier is when we do start duplicating the tree well that's running off the same object so this is normally projecting from here so that's no good we need to duplicate it with the empty object which is adding an extra level of objects we need to keep track of so you know that does work but it'd be nice if we didn't have to do that and actually we don't we don't need the target object at all we can have the object use its own origin point the problem is it's down here if we had kept the empty object and move that to zero you know that looks the same but the modifier does come with the option to offset where it thinks the origin is so we can look at this empty and copy its height on z and put that in z and now we have the same thing as we had with the empty and again that's working all right on the z rotation but there's a problem when we do other sorts of rotation it's at an angle it's wrong and this is something to do with how it's doing the offset math and its order of operations so this doesn't actually work that well if we want to have a little bit of rotation in other axes which we might want to have or maybe you don't but i still want you to understand how this stuff works because all of these concepts apply to other things as well so our first alternative option is to instead make these radial normals in the shader we can get the object coordinates of the same empty object but they aren't normal yet what we're looking at here is the object coordinates and coordinates are position whereas normals are an angle and of course we run those through the normalize node and then we do have basically the same thing there's some very subtle differences because one is mesh calculated and while shader calculated but we're not really going to worry about that you can check this like differences between vectors by plugging them both into a distance node so you can see black is where they're the same and white would be uh well white would be one distance one away just getting you the it's comparing the locations in space um so yeah this isn't very bright there's only very subtle differences which i think just has to do with linear interpolation of normals so effectively this is the same thing you won't be able to tell the difference visually so the coordinates though because we don't just want normals we want coordinates of our tree so that we can do things with it we'll get into what later but that is what we have what we're seeing here is this is the distance on the x-axis from the center of the object so zero up to one and then it goes greater than one so it's a distance in actual units in space it is not normalized or anything so that's useful for various things so by using this method we are getting both a normal and a coordinate with the uh modifier it was giving us our normals but we'd still have to go get the coordinate from somewhere else so we might as well make the normal out of that too and just like with the modifier we don't actually need to use the empty object we can just use the texture coordinates of the actual tree the leaf object and then offset them by the amount to the center of the leaves so this is subtracting the z distance the z location of the empty so that's giving us the same point in space it's a bit counterintuitive you might think that it should be added like if you're starting at zero then you would add 4.5 to get up here right but actually what you're doing is you're telling it that this stuff is down here so you're subtracting it from its current position because before that this is the distance from zero so we've got position relative to this central point and then we run it through a normalized node and that turns it into direction into an angle and that's basically the angle that is facing away from this point you know if you drew a line from here to here then perpendicular to that is the normal in that place so how exactly does it do that let's look at an example if you've been watching my normal series you already know about this but i'm going to do a quick visual example and this is a geometry nodes node group that is going to do that for us i'm not going to cover how it works but there it is if you're really curious so we've got a monkey and we're looking at its wireframe and we're going to give it a visual we're going to visualize radial normals from zero so every vertex in the mesh has a position in edit mode you can select it and you can look at it here it is in local space or you can look at it in global space which is the same in this case because our origin point is at zero and that position vector is an x y z we're used to those but sometimes vectors are used for position or a location and sometimes they're used for angle or a rotation what's the difference how it's used depends on the context if you're plugging it into some mathematical operation that's going to treat it as a position then that's what it is if it's going to treat it as an angle then what angle is that exactly what angle is defined by this xyz position it is the angle of if you drew a line from zero to that point so in this case that would be straight up that would be positive one on a z but for this point it would be from here to here that would be well whatever angle that is of some z and some x so if you do like this that's from 0 to that vertex and then if you do perpendicular to that this would be the normal of that position so our geonotes example here will let us visualize this here is a line from zero to each vertex in the mesh and here it is with the mesh the line is however long it needs to be to get there when you have a vector vectors have what is called a length and the length is the distance that point is x y z from zero so some lines have a longer length and some have a shorter length when you normalize a vector like we were to turn our position into a radial normal you are setting it to be one length you're standardizing all the lengths you are normalizing the length that's what it refers to so that would look like this so now all of those lines they still go through that point or try to go to it but they're all one unit long the reason it's important to do this when working with vectors that represent angles is that you can have a vector of any length be the same angle what matters is the direction they're pointing it so if you want to do math and properly combine angles or rotation information or any of this stuff it needs to be standardized otherwise the numbers are just all over the place so that is why we have the convention that normals are always normalized and when you take position of a vertex and you normalize them well what we're getting looks a lot like a sphere doesn't it and that's because it effectively is and we can actually set the suzanne to have its actual vertex position match where these lines are with their length of one and we can see doing that has turned it into a sphere it's not a perfect sphere because we have limited vertex density in some places but if it had an infinite number of vertices it would be and when we do this in the shader we're working on a pixel level instead of a vertex level so effectively we do have an unlimited amount of vertices because it's doing it per pixel on the screen instead so yeah this works with basically anything you take any mesh you draw a line from the center to each vertex then you clip those lines to be one unit long and you know set the mass to match that and you have a sphere here's what happens if we normalize the position of our leaves it turns into a sphere there you go in this case i had to subtract the offset from the origin to the center normalize and then add it back otherwise it would move them down to zero and this is how the cast modifier works by the way except right now it's doing it to zero but you know we've got the spherify option there so back to the shader and now we understand what that normalize node is doing and what the normal edit modifier was doing okay next problem when we rotate the normals don't change and that includes when we spin and remember this is a problem because these colors these represent directions in world space so yellow is y so if we rotated this around now it thinks y is that way and the effect of this if we use it with a shader is our shading is stuck to the mesh we can move it around just fine and we can scale it just fine in fact scaling isn't doing anything which is not good if you want scaling to do something and the reason that none of this is doing anything is because all of these object space transforms do not influence the object coordinates the coordinates are the coordinates within the object space so since we've rotated it 45 degrees as far as the object is concerned x is now over here so the issue isn't that they're being like corrected the issue is that the changes we make at an object level aren't affecting the mesh at all now if we transform it with an armature instead it's totally different so i've got an armature modifier and here's a bone and if we rotate that well the mesh is moving within the object the object isn't changing so now we're just rotating away from the position and same if we rotate on z it's fine because you know it doesn't move away from it but this is no good if we go back to our normals from the normal edit modifier then it is working properly we are moving the mesh but we are doing it after the normal edit to the modifier stack if we do it before we have the same problem as the object normals have so the deform of the mesh in the object needs to be after and of course with the normal edit we don't have these object problems in the same way so the normal edit modifier is already doing things to keep everything working correctly for both object transforms and transforms of the mesh within the object and we need to implement that for our object setup let's fix the object level transforms first if you've watched my video on generated face normals then you know where this is going we need the rotation of the object or any other transforms so that we can properly apply them back when i made that video we had to get them from a driver but now we have a more convenient way they are now a object level attribute that is just available from the attribute node in fact if you go into your object panel pretty much everything here is available like we can mouse over location x and we can see this is object dot location and that is the name of this location attribute we've entered location here let's take a look move it around that's the location of the object and that's location of the object in world space this is actually the same thing we get if we use the object info node this has a location output but only location it doesn't give us rotation or scale because this node is old and predates this uh attribute stuff being added i don't know if they'll phase it out or if they'll add these to it or what but at least we have these options now so we can take a look at our scale two it starts at at one if we scale down the number gets smaller down to zero if we scale up it's going larger than one but we can't see that so you know whatever and of course here is our rotation euler which again you get the name from looking here and i think you can get most of this other stuff too i'm not sure about these various like check box booleans but you can get like the color and all so this is the setup here we are rotating by the object's rotation and now it behaves properly now how about location and scale we don't need to do anything about location because normals are always relative to zero effectively so we don't need to adjust for anything there and we don't necessarily need scale but you might want it like right now this isn't really doing anything like this is still going to shade as a sphere even when squished instead of a swiss sphere yeah i can't even say that properly but if you do want it to squish which the normal abnormals do then you would just multiply by the scale now that's gonna squish it's hard to see but it is doing that thing yeah it's been easier to see there i do a really big one and of course if you pop it off there you go okay so object transforms are accounted for now how about other deforms those still aren't working because this is moving within the object and the point is defined in object space so we got to do something about this let us continue to descend the node graph down to our next snippet this is a different formulation of the same thing it works in object space and it does not work when deforming the mesh but it's bringing us a step closer so what are we looking at here instead of the scale and rotation being applied to the object texture coordinate minus the offset to get up here we're just taking that offset applying it to that and then subtracting that from position and this is important because this texture coordinate is object data it's positioned relative to the object and this position is also positioned relative to the object but this is mesh data and it is mesh data in world space which is what matters here whereas this is object space so these look like the same thing they're both telling us the position of the vertices but this is the position of the vertices in world space so things change as i move the object around and this is the position of the vertices in object space so things don't change as i move it around so that object versus world space position distinction is very important and it does solve our problem in a minute but for the time being it introduced a problem if we move the object so now we do want our object location we're just going to add that and problem solved so the reason we still have this problem is that we are defining this point in space here z 4.578 as the center point that gets adjusted when we make object changes it does not get adjusted when we deform the mesh so we need a way to define the point in the center of all the leaves even when we're moving things around and with geometry nodes we can do that it's actually really easy let's grab that there we go it rotates it scales it rotates on weird axes rotates on oh z perfect no matter what we do to this it's always going to be measuring from the center of the leaves what i've done is used geo nodes to get us the bounding box center for the leaves in geo nodes you can have it output the bounding box we stick those together so we can really see properly and so no matter what happens to the leaves we now have the bounding box the furthest point around it and it provides us the bounding box node gives us the minimum and maximum locations the edges of the box so if we average those mix them that gives us the center so that is what i am outputting with this attribute and the shader that looks like that which is about the same as that it's very slightly different now it does move a bit as we transform the mesh but that's fine and you know it doesn't matter if we're making object or mesh level deformations everything keeps holding up it's always just going to give us the point at the center of the leaves and all of our the stuff is fixing all of the other issues with object transforms so this is the complete setup so the bounding box center isn't the only way to do this we could have some other point where we could compare the undeformed version of the mesh like the under form position to the deformed position and thus apply an offset or whatever there's a bunch of ways you can do it bounding boxes too it's very convenient and good for this use case of a tree where we just need radial normals from one point if you wanted to do like a character with limbs and you wanted to do like this for every limb that'll get really complicated although you could technically do it now this bounty box center trick will also work if we're using object coordinates that's still fine when we're making deformation changes but then we run into problems when we're making object level changes because we're already cancelling out object stuff so there's not really a combination that works well for canceling object transforms and using object coordinate so that's why it was important to have the world space position also while we're here something to note is a lot of these things like we could get position from geometry nodes as an attribute 2 instead of from the geometry node here and we can also like use geonodes i've got a group here where this is doing object coordinates from geometry nodes if we wanted we could use drivers and get to get the uh lock rotten scale and do this same fix in the geo nodes themselves the reason i haven't done that is because it's not as convenient and that is because geometry nodes does not have easy access to these attributes because these are object level attributes so you can see that we've got them on object and actually i'm going to change them to instancer instancer means that if you have multiple instance copies it'll use the instance object first and then if there isn't an instance then it'll go to object so the bounding box center is geometry position is geometry but these are instancer aka object in geometry nodes we can input attributes with the named attribute node but these are only for mesh data attributes so it cannot access the object transforms you can get them from the object info node but only if you select your object in it or you know in the group input so you can do that like here it's got leaves if we now duplicate this it does know it was referencing itself so it will reference itself again in the duplicate but i'm not sure if that'll hold up when doing like instancing within geonodes i haven't tested that yet the point is you probably can achieve basically the same setup into your nodes and save yourself some compile time but it's going to get complicated too and it's not really necessary here but maybe we'll come back to that if i do a second video that actually gets into into um mass instancing these things so yeah there's a lot of ways to do what we just did you can do stuff in the shader level or on the geometry level and this kind of pros and cons of both we're just going to go with this because it's simplest so i've put everything in the group we've got our coordinates which will let us get the position of things relative to the bounding box center and keep with all our deforms we have our radial normal and now we can actually use our real geometry normal because i've disabled the normal edit modifier before they were getting you know sphere sized and we'll want those when we get to the leaf texture so we're back up at the main setup and everything looks exactly the same so far but now it won't break when we move things around or when we duplicate the tree and make a bunch of instant copies and we have proper coordinates that don't rotate with the tree they stay in the right position but they don't get messed up and we have our original normals so it looks like nothing much has changed but now we can get into some real fun of course as my regular viewers know my idea of fun is normals so i've made a new group that we can mix some normals in so far we've got a noise texture which looks like that which right now is not much we are mapping the noise texture with our coordinates we just made so that means as we move things they stay in the same orientation relative to the point they're being projected from regardless of object or armature to form uh so that wouldn't look very good if you're planning on like animating moving the tree in this way but these are going to be used for normals so we do want that behavior if you're going to animate this you'll have to do some more stuff but that's beyond the scope of this tutorial this noise is not usable as normals yet though we're going to need to do a few things to it first of all let's turn down the scale a bit i'm not really going to worry about like the detail of the stuff or the roughness at the moment but we need to map it into the proper range to be normals which is minus one to one and we do that with good old vector math so right now it's in a zero to one range so to get it into minus one to one first of all we subtract point five and you can mouse over and hit ctrl c to copy and then paste which is handy so now it's in minus point five to point five range so to make that 0 to 1 then you multiply it by 2. so that has effectively expanded it to fit the right range now that looks more familiar so we can go ahead and output that in our normals and plug that into our shader right now and enjoy this glorious noisy mess and if we have the full stack on well that's noisy and it's kind of lost its real shape because we've basically randomized the normals to just point in all sorts of crazy directions now remember this remap to minus one to one is critical for this to work properly if it is in zero to one range well zero to one corresponds to only the positive values on each axis so that gives us normals pointing in only these directions like only um this quadrant of the grid so if we want this to point in all possible ranges then you do need that remap and that is what we want because what we're going to do is take our sphere normals which i didn't bother passing in because we can just make them again and we are going to mix them with this noise now when we play with next factor we are introducing some bumpiness into our shading it's kind of like a bump map actually in fact if you had plugged the fact of this noise texture into a bump map node you get basically the same effect except it would actually be lower quality now we're only going to want a very small amount of this and how much we want kind of depends on the scale of the noise let's turn that down even more so my goal is to kind of break up this visible like uh just solid band so a little bit of noise goes a long way in this case let's do just we'll just do point one so that's quite noticeable on the sphere on the tree not so much so you're you kind of have to judge the right amount we can move our light around a bit and check it out it's starting to look quite good i think maybe a little bit more let's try 0.15 so this is where you actually make artistic decisions to make that a bit easier let's turn this into inputs and we might as well get the scale in there too this part of the point of doing all this is so that we can quickly test things and see what it looks like about like a high fat at a very low scale like just a little bit of waviness there anyhow you'll have to play with that and decide what you like i'm going back to these values for now so if we want to duplicate and instance these trees i'm copying with a alt d so it's a instance duplicate the noise is the same on both and we can't have that so let's get some randomness in here we can use object info and random but where do we put it we're going to use 4d noise which has this extra input w w is also called phase i think so this changes the noise pattern because w is time the fourth dimension is time so do that and now they have different noise patterns once it compiles that there we go they're different i'm going to make the noise a bit more interesting like i did in my previous setup we're going to add that and we're going to make ourselves a random seed input just so that we can control this from outside the group we don't need different random values per leaf in this case one value for the whole object is fine so we'll wrap that plug that in there and these compile times are really starting to add up which is how you know you're watching one of my videos so i've cleaned the group up i've put roughness as an input so we can play with that too uh overall yeah this mixing noise into your normals is a nice way to kind of break things up a bit it's broken up that spherical look which is exactly what i wanted so that's a fairly easy and low effort way to add some detail now let's look at another way of adding detailed normals that is complete blackmagic so i've got a normal map texture of my leaves which is part of why i modeled them as geometry so i could make this and here's what it looks like i've got the same uh randomized tile setup is on the alpha texture i've projected the sphere's normals from the front and i've got this other plane just so we can preview it easily and on the leaves it's kind of a mess and we can run it through a normal map node and now it is normals and it's still kind of a mess we can make it somewhat less of a mess with our invert normals on back facing trick that helps so like on this plane now it's the same on both sides and it hasn't changed the sphere because that's not back facing but it's a bit less of a mess and we can go and plug this into our shader if we want and now we have all this crazy leaf detail it's pretty advanced actually and it's not very useful because the normal map is on top of the mesh's base normals so a normal map like this is called a tangent normal map it takes the information stored in the normal map here and it rotates your normals by some amount based on this you actually remap this this is a value between zero and one you remap it to minus one to one and it is the amount to rotate your base normals the normal map node is hardwired to use those normals and to do the rotation based on tangents which are based on a uv map i haven't checked this because it's uh it defaults to your first uv map so that all works fine as long as you're using your basic mesh normals so how do you use a normal map with custom normals or are mathematically made normals and normally you can't it's not really a supported feature the normal map is hardwired to certain uh your base normals and their corresponding tangents and if you have a custom normal like from our normal edit modifier it will work but there's actually a bunch of distortion it's hard to see in this example because it's just a leaf and we have a ton of them but you can see like this is kind of fuzzy that's not the proper shape we'll be able to see a comparison in a minute the reasons this happens are complicated and technical and i'll be covering them in my big normal series but basically the base normals and base tangents have to be matching they correspond to each other when we do a custom normal like the normal edit modifier or data transfer or vertex normal editing that changes the normal but not the tangent so then they don't line up correctly and things don't map quite right but we can get around this problem so we'll turn the normal edit off and we'll grab this group here normal to surface gradient it takes a base normal and it takes a custom normal of some sort and it outputs this so the base normal looked like that let's use our plane here or a sphere the normal map version is that with detail added and what the surface gradient is is the difference between the two this isolates only the things being added by the normal map but in world space instead of in tangent space next we have this other group where we put in our surface gradient and we put in whatever normal we want and it adds that difference onto that normal instead so now we can use this in our shader and have the full quality without distortion if i toggle the normal edit modifier on and off that introduces the distortion and now you can really see the difference so this is how it's supposed to be and this is what happens when your normals your custom normal doesn't sync up with your tangents because blender does not have custom tangents if i put a normal edit modifier on our plane here you can really see how badly it butchers it so surface gradients are just amazing it allows you to isolate bits of normals offsets of things differences between things you can use these combine multiple normal maps if you had multiple normal maps on the same thing you get the surface gradient of both and then you can just add these together and then run it through this so they're super powerful and versatile and we can even do this on top of our normal with the noise in it instead because it is just stacking that rotation now this is a bit too strong so let's tone it down a bit we could mix this back with this but we can also just mix the surface gradient with 0 because 0 does nothing and we're really stacking up those compile times again so that shuts it off completely so this is another case where we probably want only a very low value just to bring in a little bit of that detail but now up close we've got a little bit of actual leaf detail going on all right that's cleaned up now i've stuck the normal map texture and the initial surface gradient conversion in this group detail surface grad and i'm using it in the normal mix group here and i've added a factor which is just multiplying it and that's a separate output right now so now we can scrub our detail level on and off i'm not really going to go into how this works in this video here is the group to take two normals and get the surface gradient of the difference it's not very complicated but it would take a while to explain exactly how this math is working and why you need to do this and you know as opposed to other ways of getting differences or mixing and the group to actually use it is incredibly simple i will be going into detail on how all of that works in my next customizing normals video though so check that out if you're interested but here i will show you how i created the leaf normal map so the reason i modeled my leaves out as full geometry instead of just drawing them was so that i could go back and get normals or ao or whatever else i might want to do for them so how do we actually get our normals baked properly to a normal map well the answer is that we don't really and i mean if we go to cycles and try to bake with the normal bake system it's just really annoying to do it properly you make a plane you select everything you have to set up a text to debate to on the plane and all that and then you have to like get extrusion correct and it's really a hassle you can do it but it's hard to just get it done without distortion what i want is something as simple as what i showed for the original alpha mask which was just they're already flat so i just want to render this so i've just made a setup that lets me do that a tangent normal map is the difference between two sets of normals around the axes defined by the tangents and i'm not going to explain what all that means here i will be talking about that in a customized normals video at some point but basically i just made a note group that just gives you in the viewport exactly what you would get if you were just basing these and then there's orthographic camera with very simple settings size of one because my whole object uh plane is set up to be one by one i've got my reference bounds and that i've added this bake plane to fill in the background color so then you just f12 render that and that's your normal map that's that's it no baking hassle and the reason this works is because we're working with something that is already flat you do want to make sure that you save it out properly and don't have any color management make sure your view transform is standard not filmic because this color information is it represents mathematical information it's vectors it's not color so when you save this you want to make sure like save as render isn't checked because that applies color transforms and you want rgb you should be fine with either 8 or 16 bit do 16 no 16 to be safe i haven't really compared it this is the same thing as when saving regular base textures you have to have enough bit depth to contain all the normal information i will also be talking about all the details of the right formats and bit depth and everything like that for normal maps in some future video but i'm not going to cover all that here the background color does need to be just right it needs to be 0.5.51 and this can be a bit tricky because watch this if i copy this hex code and then i paste the hex code it's actually off by a tiny bit due to i don't know if that's a floating point error or something to do with how the hex code works but you are going to need to manually type in that 0.5 i don't know if you can eye drop it right either so i guess i need to re-render this because i didn't have that correct in this setup i'm not going to try to explain this entire tangent space difference group here either here's what it looks like inside if you want to build it for yourself it's a bunch of vector math the really quick version of what this is doing is so the surface gradients we looked at before gave you the difference between two normals in the world space what this does is it's getting the difference between two normals in a tangent space the tangent space means instead of x y and z being what we're used to it's x y and z relative to something else so like if you go into edit mode and you start transforming something in a global space then when you lock into x it's you know global x and instead if you lock it to normal and then transform an x it's x for this the plane of the face or you know y for the plane of the face and that's essentially what tangent it and by tangent are for so x y z in global space are the three axes and then in tangent space x y z are defined by z is the normal and then x is the tangent and y is the by tangent so yeah all of this is just rotating things by some amount but in some axes relative to the face instead of relative to the world that's what a tangent normal map does so what these inputs here are is defining what those other axes are and in this case it's very easy because we've got a we've got our leaves and we're comparing uh we want the difference in rotation between essentially the leaves and a flat plane which is pointing up on z so one on z that's just pointing up and so we're telling it the z-axis is actually world z and in this case we're telling it that the uh tangent which is the x-axis is one on x which is just the world x-axis and then the normal is the actual normals of the mesh so that's our input it's very simple this could be a different object but what makes this easy to use is that we're getting the difference in tangent space between these and flat and our tangent space is the same as our world space so that's why we don't need fancy baking that's really comparing the measures in a complex way we can just easily like we don't need another mesh as an input here we don't need to like transfer normals before we can compare them or anything because we're just comparing it to flat and we know what the normal for flat is and the tangent and yeah we'll save the rest of tangents and normal apps for later video but the point is if you just want to take a snapshot of detail that you model flat and just get a normal map of it without going through the whole obnoxious baking process just build this group and do exactly this with these inputs assuming it's pointing up on z if you had it pointing you know this direction down y instead then instead of one z you would put minus one y it's whatever direction is facing your camera and then that's it our next big topic is density and let's start with the actual mesh density before we get into uh faking volumetric density so i said at the very beginning that i probably had more leaves than i needed and if we look at edit mode like i really have a lot of redundant leaves in fact i have 26 000 leaves you don't need that many leaves um how many do we need that's a great question i don't know i just make the shaders i'm not actually a tree expert so i've made a bunch of copies with less leaf densities so that we can just look at them and make some informed decision the difference here and here isn't much except around the edges where things have gotten a bit a bit too few and i did this by just uh selecting everything and doing well doing a um select random with a 0.5 ratio so that gave me uh half the faces and then deleting that or like some other ratio so that's how i got down to 13 000 and that doesn't mean you deleted at a very good distribution so the problem with these comparative meshes is that the distribution of leaves is not good it would probably be better if you were making it with a different leaf setting in sapling or whatever you make but basically we need some amount of density before the shader starts looking a bit weird like here yeah it's weird at the edges but it's also weird inside and this one is still pretty solid inside so i would say you could have a lot less than 22 000 leaves you could probably take it down to you know six seven eight thousand at like highest and then if you had a better distribution other than just random you could have significantly less and there's a lot of other optimization things you can get into like replacing the interior of the tree with spheres with leaf textures on them instead of planes that's called using shells or you could have something like if you're generating the trees for a certain camera angle and you know it'll only be looked at from the front then you can just delete the back or something like that or you know if you want a really low poly tree you take this tree and then you bake it to a texture and you can still use our normals on it because they're being projected so there's a lot of stuff you can get into that's really a subject for a video on instancing and optimizing the tree i'm not going to get into that here we're just doing the leaf shader but i want you to know about it that what i've done here is excessive because everything i'm doing here is excessive next let's look at shader tricks to imply more density and volume to this tree we already added some noise into our terminator to imply a bit more shape and we've got our terminator position less than the usual 0.5 in order to imply some light passing through but since we have our coordinates we can get basically the full volume of our big cluster of leaves here and we can do a lot with that here's a new group we can work in we're going to take our coordinates and the basis of a lot of this is going to be the distance node which at first appearance doesn't do anything but that's just because our values are so much higher than one but check this out let's normalize our coordinates which gives us our typical normal remember and get the distance between the position coordinates and the spherical normal now what do we have it's a bit hard to see because our transparency isn't on and i have so much leaf density but if we start mapping that range a bit we can see that what this is giving us is a gradient from the center out so it's zero at the very center out to one depending on what range i map this to so this means we can mix things based on how far they are from the center of the tree and since our tree is spherical that's basically simulating density so for example we can make it brighter to the edges or we can desaturate even more or we can address the hue or you know any sort of effect we can think of or we can apply this as a mask for any of our other effects for example here i've set it up to mix between two values for ambient strength so at the center of the tree we can disable the ambient light completely disabling it is probably too much it shouldn't go black in there but generally there should be less ambient light getting into the middle so maybe we'll have at the outside to get to 0.2 and in the center it's only 0.05 so that's adding a bit more dimensionality to our tree in a very simple way or we could adjust our terminator position a bit a major change in that will probably look weird but a bit of subtlety is essentially darkening up the middle again there's always just directly applying it into the shading the darken effect causes it to use whichever one is darker but unlike multiply it won't make things darker than the darkest value too much of that is bad but again a little bit of that how about something really weird like steps based on it if you wanted to stylize the tree that way or whatever that steps and then still using the darken pretty funky but who knows there's just a massive amount of possibilities here and it doesn't only have to be shading in colors we can mix our normals based on that how about no detail effect in the middle because you don't really need leaf to detail in the middle but then turn it up at the edges that kind of brings it a bit to the foreground for whatever angle we're looking at or we could do the noise you don't need as much noise in the middle and what the edges i don't know i don't know what looks good i haven't played with this that much but you should try it out and see what you can think of whatever we end up doing with it we probably don't want it to be too linear so that's where we could color ramp it to you know ease it or we can make adjustments on the color ramp or in the map range there's also like rgb curves we have the float curve here which is perfect for this if you wanted to you know like raise it a bit here and lower it a bit there or you know whatever you want to do this is the place to really look into all these ways that you can adjust things with the mask and of course this isn't our only masked option we can also just take the coordinates and you know separate xyz and turn these into masks from some range to some range and this reveals an issue we may run into problems with which is that we are manually defining what ranges we want to use so we know the x dimension of our mesh is 7.308 so if we wanted to make this from this point like that point then what we would do is make it from that divided by 2 to that divided by 2 or minus that and now we've got black all the way to white across the x-axis and we can do that with any of these axes now this isn't 100 precise because this dimension is from here to here so it's precise if it's exactly the same size on either side of the x axis but it probably isn't so you know it's not going to be entirely precise but it's close enough because our tree is spherical if the tree was in more complex shape then getting masked to various different parts of it would be more complex so that's another reason we started with this one and since we are defining our mapping size in world space here we could run into problems when instancing this tree if the size is very different there are ways that can be fixed by getting more information from geometry nodes or like normalizing the coordinates to zero to one before using them and i'm not going to talk about that because it would be like another 15 or 20 minutes so we'll leave that for if i do a video on actually instancing and duplicating trees for now i'll label this center mask i think 2.5 is a good amount but let's also get a mask from the bottom up because density generally doesn't just occlude from the center since the light is probably coming from the sky we'll do some fake occluding at the base you could adjust these further but i think that looks fine for now and i'm clamping both of these so that if i'm uh ramping them more later it doesn't cause any issues i've created an output for the center mask and the lower mask because i'm not exactly sure what i'm going to do with them yet but i also want the two of them put together a combined mask and this is a good place to use the darken node because it gives you the darker of the two values whereas if you use multiply then areas where they're both dark it doubles the darkness essentially and here it doesn't have as large an impact you can use whichever you feel is appropriate for what you're trying to make though and you know i guess i can do this and save the compile time oh and before i forget i was using this mixed value node before this is just a mixed color node but with value input sockets so that you can type in a value without having to add multiple value nodes so that's all that is i'm not going to use these masks for anything quite yet because there is one more way we can get some density information and that's good old ambient occlusion which does not work until you enable it here ambient occlusion is great because it will get us the more occlusion in our leaves and we can even use it with our custom normal to make it a bit more spherical but there is something you have to watch out for let's get a diffuse shader and we'll use our alpha so we can see it a bit better and i have disabled the sun lamp and let's go over to world and turn on some indirect light that's our only light source but we're getting ao on it so the ambient occlusion node doesn't work unless you enable ambient occlusion in render settings but once you do that it automatically applies these settings to any use of the diffuse shader and i assume other shaders too so if you are using a version of this setup that does use a diffuse node or anything similar then you need to turn that off by turning all that down and there can still be some artifacts so you really have to turn everything here off if you're not actually using any world light though then there's no problem so what we're going to do is basically implement the same thing that ao is being used for on the actual world light for actual shaders but for our ambient strength over here keep in mind though that some of these settings do affect the behavior of the node i think bounce and bent normals don't but trace precision does a bit hard to see we'll look at it when we have a better example so this is part of why i'm just not using the world light at all again and not using real shaders just another bullet dodged so i've made a group to put the ao in as well for organizational reasons and i'm going to darken it with the density mask and then i can remap it and what's a lot of fun about ao is you can also give it a custom normal so with just the base mesh normals it's not much to look at but here is our radial normals and what i've decided to do is that my lambert shading my actual shading is going to use just the radial normal and not get any of the normal map detail so i've changed what was previously the detailed version over to just the ao normal and also changed the name of the effect when we turn that on we can see that our ao is getting the normal map so it's picking up some of that shape from the normal map the reason i've chosen to do it this way is because i think the normal map was just too strong on the main shader and it's probably not really necessary at all but you know i wanted to show it so i've put it the setup so i'll just use it here but this is a fairly arbitrary decision i'm making just like the density masks we can use the ao or pretty much anything the obvious thing of course is to take it and multiply our ambient light by it and kill the ambient light where the ambient occlusion occludes it and i'm going to turn the occlusion from the density masks on but this is a bit too strong i don't want to completely murder the ambient light everywhere otherwise you know the scene could be very bright and that's always going to end up zero where the ao is black so let's remap this a bit now it's point five to one so in the areas where the ao is darkest it's only getting rid of half the ambient light so that gives us a bit more detail in our shadows which i like density mass may be a little too strong on the ao effect let's make that point five because this is where they're coming into the pipeline to then be multiplied over the shading too yeah i'm not sure what i want there two thirds let's do even more with our ao and density in our combined colors i've added at the very end a soft light node which is this to understand what soft light does let me show you overlay first so as we turn it on in areas where the ao mask is dark everything gets darker and where it's light things get lighter and the reason that i've mapped the range from 0.51 to 0 1 is because remember our incoming ao was already mapped to be 0.5 to 1. so it's really bright if we don't have the map range doing anything then we're only seeing brightening effects this is because overlay is either darkening or lightening based on if the mask is a value above 0.5 or below it so right now everything is above 0.5 so it's just brightening it and when we remap it properly now it's the full range so some areas get lighter and some darker soft light is very similar there's a bit more to it i don't remember all the details but basically it's darkening where your input is dark and lightning where it's light it handles color a bit differently and it is well softer there is also linear light which again is similar but it's way too strong for what we're trying to do here so you can look up the details of how the math on these works if you want to know more now in this case i'm not going to remap it i do want it to basically just brighten and that is because we're already getting detail from the ao in the darker areas by cutting down the ambient light but we don't see so much of that in the brighter areas with a soft light we do now i could use a similar effect i could do like a division or add or screen which would do much of the same thing but this is already working and this will keep working with various other settings and yeah i mean you can do pretty much everything in more than one way so right now this is brightening up my darks too much so let's mask it based on the shading gradient i'm gonna go through this mix node just so that we can control it properly so now we are brightening things up but not too much in the shadows still a little bit but not much and we probably want a pretty low fat on this because you can see how much it's doing too strong and of effect will make our object have too much detail i want just a little bit for close-ups and like when you're further back you're not really going to notice this anyway or we may disable it further away i've added a multiply on the shading gradient to control how much to do it i think i'm going to go for just the third that looks like a good amount and this could become a a fak input on the group but i think it's fine just like this so that's given us a little bit more nuance in our light areas based on the ao so ao doesn't have to only be about darkening i think that's all i'll do with the ao in this setup but i've also decided to use the density masks to make the noise inputs a bit more interesting so i changed up the outputs in the density group because i was only using the combined and i'm using it as a mask for scale and roughness these are the values i had before so the first number is closer to the interior of the tree let's try a really low number and see what that looks like and make it a bit higher at the edges and then the second one the roughness maybe rougher or less rough of the edge i guess it should be less rough in the center and then rougher at the edges so these are really subtle changes that i'm just kind of doing for fun it's not not visually that visible maybe i should try maybe i should do something bigger to really have it be noticeable but whatever you can play around with it and speaking of small features that are only really visible up close sometimes you want to make sure you turn those off further away so for our last feature we're going to be looking at z distance in stylized styles generally things that are far away are not very high detail and to some extent this is already losing most of its detail when we zoom out because it simply gets smaller but there's still quite a bit there there's more than you would have if you were say you know drawing this and it was that far away also the alpha kind of dies if you get too far away so let's add a control that lets us turn off some of our effects the further away we go view distance tells us how far something is from the camera and i call it z distance sometimes because it is the z axis of the camera vector also with orthographic on it doesn't really work you need to be in a perspective view because orthographic kind of by default has no z distance and right now we can't really see anything because these are real world values and our tree is pretty far away it's at 0 0 0 and right now our camera is at -36 so it's just too far off to actually see what's going on so of course we need to map the range so we've got a map range node i've stuck the inputs out here so what did i say the camera was it is at -36 so 0 to 36 and there is data about the tree so there's a couple ways we can use this distance one would be to get like a normalized mask of the part of the tree closest to the camera and a gradient to furthest for that we would need to get the camera's position and use that to map things i'm not going to go that far but you know if you know the camera position and you know the tree position and you know like the bounding box for the closest and furthest all of that information can be gotten like from geometry nodes we can get the bounding box we've already got it so you could build that if you wanted a normalized distance pass upon the tree but i'm not going to use it that way here i'm going to just set it up as a way to control certain effects coming on and off depending on how far away we are from the tree let's unpin our sun and i'm going to pin the camera so we can keep track of its distances easily right now we're at -25 and i've hooked this up to the noisemix fact for the normal i had that noise fact at .154 so the way this works is when we are at zero distance this will return one and then once we get to 36 it will return zero so let's set this to like one and zero so when we're up close we have the full fact of the noise as we zoom out it turns off and it's fully off by the time we get to 36. so now we ask ourselves at what distance do we still want to be fully on i think i i think i like my 0.15 noise out to about about here so that's 43 so we're going to start this at 40 and then i want it to be gone by let's say here so that's 90 40 to 90 and then we can set that to zero and now we have our 0.15 noise as long as we're within 40 and as we get further away eventually it is gone but it's a pretty subtle effect which it should be i think actually i'll make that a bit stronger i'm going to change that to 20 and then change this to 0.25 so now it's even stronger very close up and let's have it be gone by 70 i'd say so that's pretty good so now we don't have quite as much visual detail on the noise at this range before we have that much and now we have that much i've moved the mixed value inside the group and rename some things but technically we don't even need this we can just define these values here in the two min and max now note that currently this is going one zero instead of the default zero one that's why it is white when we're right up against the object and black when we are further away i chose that behavior the default would be zero linear zero distance and one away and that's because it seems more intuitive to me for the noise min to define the value up close and the max to find the value far away but you could just do this instead and reverse these and it's the same effect either way it's just a matter of how you want to format the values on your group or the user interface actually i'm just going to rename it to noise close and far and reorder those and nobody has to know so now it's the most user-friendly and we'll put 0.25 there and rename those other inputs and we are looking good i've set one up for the ao normal detail as well so now it's at full strength up close then once we get to 15 it starts interpolating down until we're at 35 that's all gone but there is a problem which is if i keep going it comes back but it's inverted and this is an issue with the map range node things are basically wrapping unless we clamp so that fixes that you can use this to control as many of the various features we've built as you want or you could just mix to some totally new thing like if you wanted to eliminate almost all of them you might want to have it be that when you're this far out that it's just a single shader with just maybe the color shift and nothing else so you can set this up in whatever way you like i just wanted to demonstrate the concept i've added one more that is just mixing here which ignores the saturate and the brighten with ao and just goes back to the regular shader so that's again reducing detail a bit as you get further away i didn't bother setting that up with inputs because whatever also i did have the noise valve close and far had the name switched yeah so there's a ton you can do with this if you want to keep in mind that this is only a artistic level of detail change this isn't a like a lot for performance you're still stacking up the full shader in fact this is a more complex shader so if you were using a proper like log system with different versions of the asset that were getting turned on and off at different ranges or something then you wouldn't need this this is purely a artistic thing also keep in mind that these are all linear effects right now it's all linear gradients you could put these onto like smooth or smooth step you can step them uh you could put them through rgb curves to change up how fast things go on and off or color ramps you could do more complex mixes to go through multiple different effects whatever okay i think i'm ready to call this done we've thrown a ton of different features into the shader they're all in these different groups i've set it up this way so that it's easy to see what we're doing and so that if you want to try using this it's easy to just take some whole part of it out and you probably should because this is really heavy and slow in compile time and we've basically got enough features in here for a high detail up close tree which this isn't really intended for and we probably don't need this many features when you really you know are instancing like a whole forest and you zoom out of course the reason we went through all this stuff was just to teach you about a ton of different things get them on your radar you can use them where you need i think it's pretty neat that we got all of this done and have all this detail in it and we actually used one shader note you know normally when you see fancy shaders there's like a million textures and shader mix and you know principal b sdf gloss and all that stuff but i guess what i wanted to demonstrate here is that a lot of shader art is just about the things that come before the shader node not necessarily the node itself or in the case of npr it's just diff mixing different things based on various different input properties and since we built this spread across a bunch of different groups it's easy to take out parts that you don't feel like using if you actually intend to use this crease shader which i would suggest restructuring it a bunch first in the file release i am going to put in a copy of this material where it isn't all in groups it's going to be just one thing because otherwise you're gonna have a ton of group bloat in your file i've got all these and then we used a bunch of these and then i have earlier reference versions that i've been looking at as i recorded this so yeah i'll put that in now i assume that some people watching this are here more for the tree part than the just like esoteric shader stuff so the next question for the tree enthusiasts is well how do i make this into a forest how do i actually use this with an instant setup and i have experimented with that i've been trying to build this whole thing with that in mind so here's a collection where i've made a bunch of copies of the tree these are instanced uh copies so alt uh alt d to make more of them and it works just fine with these i'm just manually giving them you know some rotation and scale differences and the shader we've built is perfectly happy with this now if you really want to get the most out of scattering and procedural generation you're going to want to use geometry nodes so i've included an example of that because i was playing around with it so i've got this uh grid which has been kind of scrunched up just to get some randomization and it's spawning the trees based on that grid here is the geometry nodes for that so it's inputting the instance grid and the leaf object it's uh transforming some things actually i don't think that's even doing anything right now um yeah this is all beyond the scope of the video just to give some idea so it distributes a bunch of points on the grid that it instances copies of the leaves on the points i've only set up with the leaves not the trunks right now that needs to be solved and it it works there are still some issues though that would need to be sorted out like here remember we're using object location from an attribute and here i've got it set up with the node as if we use the attribute it's doing it for the whole object that the tree is instanced within whereas this node is using the object of each instance because under the hood instances are their own object effectively so you need to feed more information from geometry nodes or figure out what this is and uh same thing probably for some of these other attributes so we're like halfway there this isn't a complete setup but it's most of the way there to working with mass scattering while still keeping our objects at like position generated normals or of course if you just approach normals in a totally different way then you might not have this problem so you know there's a lot of factors in this and you can do things in like five different ways which is part of why it's difficult to figure out so i may do a video about actual scattering and stuff at some point in the future but it's not going to be a high priority for a while what i'd like to make in the long run because i do want to be able to do like nice trees is something with a bit more granularity so like right now this is one blob of leaves that's getting copied but even with some randomized transforms it's a bit too similar what i think would be fun to make would be a tree where like you're instancing every branch it's a branch level instancing with its own normals so that could have more detail and support more tree types beyond a sphere and then that could have enough variety there's a lot of people who are like working on procedural trees and generated stuff in geometry nodes though so i wouldn't be surprised if one of them just comes out with a better tool before i really get into this more on our instance trees that we made manually this location issue doesn't exist it's only on the geometry nodes version so i've made a copy of the leaves with a copy of material which isn't node group based it's all one big group and that looks like this so this is if you actually wanted to use this i suppose and it's pretty crazy and you remove the groups you realize just how much stuff we've put here so that all of this stuff i'm gonna check up on gumroad so if you want to save yourself some time building any of this stuff yourself or if you just like my content and want to make a little donation i'll put it up for a couple of dollars and if you are following me on patreon already then i'll be sending out a 100 off the gumroad code as usual and as always feel free to leave comments or questions here or in the video description there'll be a link to the blog post for this you can find my contact info there or on the youtube about page you can email me direct message me on facebook or twitter whatever and of course there is also patreon thanks for watching and i'll see you in the next video
Info
Channel: aVersionOfReality
Views: 15,339
Rating: undefined out of 5
Keywords: anime, manga, toon, cartoon, toonshader, 3dtoon, 3dcomic, 3dart, blender, normals, 3d, uv, texture, npr, game
Id: 5itzrrhg8TE
Channel Id: undefined
Length: 149min 30sec (8970 seconds)
Published: Mon Aug 08 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.