Jump to content

havenphillip

Members
  • Posts

    550
  • Joined

  • Last visited

Blog Entries posted by havenphillip

  1. havenphillip

    Shaders
    So we went through a lot of fragment shaders. Did some vertex displacement. Went through tessellation. Now, some geometry. I don't have much to say about it. Just keep poking at it with a proverbial stick and eventually situations start to look familiar and you know what to do because it's similar to stuff you've encountered before. It does seem to me that there's not a lot of variety in geometry shaders. There's a bit, though. Enough to make it interesting. But grab these shaders and you'll have the gist of it.
     
    Here's a normals visualizer. This is like the first geometry shader everyone makes. The blue lines are the faces, the yellow lines are the vertices:

    43_normals visualizer.zip
     
    A simple instance geometry shader.  There's a bool in the geometry stage. If you set it to true it works for simple boxes but not for more complex shapes. If set to false the corners break on the box but the more complex shapes look great. There are two instances here and in the shader you'll notice "EndPrimitive()" after each. You'll also always see "EmitVertex()." You can emit many vertices per primitive. But once you end primitive it means you're moving on to something else. Check it out:

    44_silhouette.zip
     
    This shader uses a technique called shell texturing. In it, the geometry shader is used to duplicate the surface several times according to a height map, and with each new layer the alpha areas grow. I call this "short fur" because it's a little temperamental. If your fur is too long you need more steps, which eats at your FPS. Too short and you don't get much of an effect. I come back to this shader periodically, just trying to improve it, and you will probably be able to see why. It gets a little "twinkly" around the edges due to the viewing angle. But it's a nice little shader. Not too complex:

    45_short fur.zip
     
    Same basic idea in the geometry shader as the previous. Just set the cloud plane in the scene and attach the script and it will set it up in the sky for you. Also included the cloudless skybox material and shader:

    46_volumetric clouds.zip
     
    I want to make a LOD system for this in the future so I can make whole fields. In the pic it's scaled to about 20x1x20 and the tessellation is set at about 32 in the control stage.  There are three noise textures. One for wind, one for grass heights, and one which I used to randomize the grass blade positions so they didn't look like nice little rows and columns. By all means mess with all the numbers, but it's kind of nice to just sit and watch this one blow in the wind (also set the wind texture to uncompressed to eliminate some of that banding - that way you get a nice rolling wind).. Check the links in the shader to see how it's done, but basically you just draw one blade of grass in the geometry shader and then tessellate it. That blade of grass reoccurs at every vertex. Throw in some bada-bing/bada-boom and it looks pretty natural:

    47_geometry grass.zip
     
    I'm thinking I'm going to attempt to do a PBR shader. So I'll call that next. But it may take me several weeks so I may vanish for a bit. Let me know if there are any shaders you want to see in the future. I'm thinking after I hit 52 shaders I'll just keep posting. But at that point I'll just do it more at my leisure. There's a lot of things I still want to make.
     
    Happy shading!
     
    Next: PBR...
     
  2. havenphillip

    Shaders
    Leadwerks 4 is one of the best purchases I've ever made. I've spent thousands of hours on it and most of that time has been spent dinking around with shaders. I'm not great at modeling and animation. I'm ok with scripts. What seems to draw me the most is shaders. I love shaders. I guess in some way here I just want a place to show off my accomplishments, but I also want to feel like I benefit other people, so my philosophy here is that it's cool to be one guy who can write shaders, but it's cooler to be one guy who can help several other guys write shaders. So I had this idea that I would attempt to make one shader a week for a year - fifty-two of them - and then post them in the community. So that's what this blog will be. And who knows maybe I'll keep going.

    In the process of writing these I've scoured the internet and tried to keep track of any sources for those who might want to investigate some principle further. Many of these sources are tutorials and such. I numbered the shaders roughly with the intent to order them from basic to more complex principles. I commented sections in the shaders to help make them a bit easier to read and understand, and I tried to keep the language consistent from one shader to the next so that it can easily be seen how different parts are used in various effects. Apart from a few post-effect shaders, I start with a "noobalyzed" version of the Leadwerks "diffuse + normal + specular" shader as a base and start every shader from there - with all that I still consider myself a noob as far as coders go - hence "noob shaders."
    So if you're also a shader noob then follow this blog, grab the shaders, read the information from the links, tweak the numbers, dink around, and eventually it will start to click together. At the least you'll have a nice little stash of shaders.

    Ok so let me start with a few preliminaries. I want to bunch them up together and get them out of the way. First off, the base shader which I consider the "bare bones" shader. It is a "noobalyzed" version of the Leadwerks "diffuse + normal + specular" shader.


    00_base.zip
     
    Here's a few quick effects I picked up from various places. It's not very useful, perhaps, but it's a good start on manipulating variables to create effects.


    01_quick effects.zip
    And here are a few post-effect shaders. The contrast, desaturation, and gamma correct are all found in the quick effects shader. You can see that all these shaders look extremely similar. The effects are the only difference. In some sense all that matters is what you set in your output line (out vec4 fragData0). Simplistically speaking, that's the way shaders are. They're all pretty much the same. It's the stuff you add that makes them interesting.
    Edit: forgot to add shader 2. Texture scroll:

    02_texture scroll.zip
     
    Possibly the worst contrast ever. But hey maybe you want that:

    03_contrast.zip
     
    Desaturate dulls the colors toward grey:

    04_desaturation.zip
     
    Saturation intensifies the colors:

    05_saturation.zip
     
    Gamma correct is the way the light "is supposed to look":

    06_gamma correct.zip
     
    Color bleed is the idea that colors ought to bleach out a bit in direct light:

    07_color bleed.zip
     
    Sobel because why not:

    08_sobel filter.zip
     
    Next: Fresnel and Blinn-Phong...
  3. havenphillip

    Shaders
    Here's a cool effect I don't know why I didn't think of this sooner. This shader uses parallax occlusion and a trick similar to that in the weeper (22a_weeper). The idea is that you can get a cheap refraction effect by multiplying the texture coordinates of the diffuse texture with the normals (naturally you'd have to establish the diffuse "outcolor" after you establish the normals). It looks something like this:
    float amplitude = 0.1; vec4 outcolor = texture(texture0,ex_texcoords0 + normal.xy * amplitude); That's pretty much the gist of it. What this does is it warps the diffuse texture coordinates by the normals. But adding the normals to the texture coordinates pushes the effect to one side so I took it a step further by subtracting the ex_normal from that and the difference creates a nice centered refraction effect against the diffuse texture.
    vec2 n1 = normal.xy * amplitude; vec2 n2 = ex_normal.xy * amplitude; vec4 outcolor = texture(texture0,ex_texcoords0 + n1 - n2); In the weeper shader I added time to the normal texcoords and that makes an effect like water dripping down a wall. Here I didn't need that because this is ice. It's stuck in place.
    Once I got that established I added parallax to the diffuse texture. I used texture4 in this shader for my "outcolor" because I reserved texture0 for the little scratch marks on the surface of the ice.
    vec4 refractcol = texture(texture4, parallaxed_texcoords.xy + n1 - n2); After this I finished the color by mixing the outcolor and the refractcol by a "lighten" blend mode I found on Github.
    If you look at the normals and the outcolor in the shader you'll notice I didn't use the parallaxed texcoords because I wanted the surface to remain where its at and give the impression that there is something sort of encasing the "ice" i.e., the surface of the object - what the light bounces off of. The whole "ice" effect happens under some surface, right?
    I also z-sorted the object, which gets rid of the shaded sides (like ice doesn't really have a shadowed side does it?) and because of that I lost the specular so I added a blinn-phong to replace it. Also I added a cubemap to simulate reflection.
    I think this would work great as a frozen lake or an iceberg. Maybe even as ice cubes. It doesn't take the screen into consideration like the creek refraction does so you still technically have an opaque object. It's also parallax which notoriously has trouble with curves. I've added a few tricks so that the parallax can work on gentle slopes. You can adjust the texture sizes, the light, the cubemap fresnel, the parallax depth, the refraction amount, and the ice "contrast." If you put it on your own model you'll have to adjust the texture sizes and stuff but it's set up to work on a Leadwerks box brush so you can just slap it on one of those to quickly see it in action. The picture doesn't do it justice you have to move it around to see the effect. Anyway it's something fun. 

     
    27a_ice.zip
  4. havenphillip

    Shaders
    Hello, fellow noobs. Hope you're doing well.
    I have a few extra shaders I had wanted to get out to you earlier but couldn't because they weren't complete or they were a bit off-track. I have some more extras I want to add but here's a few for now.
    I had wanted to do a multiple lights + alpha shader but it turned out to be a little trickier than I anticipated. I finally got it, though. Haven't tried this out in various situations but I doubt there will be any problem using this for whatever you might intend it for.

    48a_multiple lights blinn-phong + alpha.zip
     
    A kernels shader from LearnOpenGL. There's a sharpen, blur, and edge detect kernel included in the shader. You just have to comment or uncomment the sections depending on which you want to use. I also included a kernels post effects shader so you can use these as post effects as well. Actually all the post effect shaders I posted can be changed to model shaders. I'm just not sure whether that's something people might want. Maybe I'll do that next so we have them.

    01c_kernels.zip
     
    This shader shows how you can add lighted areas to your shaders. I used the blur kernel here on a glow map to get a bit of a softglow effect. Nice thing about this is you can design your glow map to anything you want (provided you have a basic understanding of some texture editing program).

    01b_softglow.zip
     
    You know how sometimes you might find a cool rock in a creek that seems all colorful but then when you take it home and it dries out it's just a boring dry rock? I found a little trick for giving things that damp look. The whole of it is:

       float dampen = 0.3;
       outcolor += (-0.5 * dampen);
    ...that's it. It's a good trick for decreasing the brightness without sacrificing the colors. Increase the specular so it's nice and shiny and you get a pretty convincing noob "wet" look.

    01a_dampen.zip
     
    Use this shader to get ambient occlusion out of your heightmap.

    37a_ao from height.zip
     
    I had wanted to add a 3D version of the bepuddled shader but it took awhile to get it to a place I was happy with. When the rain hit here I decided to finish it. There are a lot of variables you can tweak in both the evaluation and fragment stages to get it to your liking. I set them all to what I considered close to universal but tweak them all to your liking. Should be fairly easy to figure out how to use this one. There's a lot to it, though. It's kind of a long shader. I included the ambient occlusion shader from above in here, for instance. It's got six textures in play. I tried to use reference puddles from the internet but couldn't find too many good examples of how the mud color and the fresnel work together. But I think the skybox brightness is biased by the color of the mud in the puddle somewhat.
    You can increase the "hillness" of the shader but keep in mind it won't affect collisions so probably best to keep them low. Also I wouldn't recommend this on a sloped surface because the puddles don't take the slope of the model into consideration (puddles on the side of a hill? The solution for this would be somewhere in the  slope blend shader [25_slope blend] but I had to call it here. Hours already into this).

    You can see the heightmap is used for a lot of things here, including how the opacity of the puddle mud changes. And of course you can affect the mud brightness and hue. I've found that vec3(1.0, 1.0, 0.95) looks like a good mud color regardless of the brightness. I tried this with a lot of different textures and with a few adjustments each time it looks good. Included a 4x4 plane. Looks like the picture if you scale it to 30x1x30.
    Notice also the dampen effect from above is used around the edges of the puddle areas:

    41a_bupuddled + tessellation.zip
     
  5. havenphillip

    Shaders
    Since I started doing shaders I've begun to stare a lot at things. I stare at the ground. I stare at walls. I stare at rocks...and when autumn hit I started staring at fog...puddles....mud... This week I've been working on puddles and fog in keeping with that spooky October/November vibe. I worked out a pretty good mud puddle shader which I'll post next but I figured this one is done and I've tweaked the **** out of it so I need to stop at some point and know when it's done. This shader is made up of the fog shader (39_ground fog) and the POM shader (27_parallax occlusion) with a texture scroll element (02_texture scroll and/or 20_creek), which is nice because if you have these you can study each aspect of the shader independently if you so desire.

     
    Since this is made from a few previous shaders, and because I feel I missed some points before, and because I'm only posting this one and I've heard a blog works well when it's somewhere between 200-500 words, AND because the shader code feels a little cluttered to me I figured I'd go a little in depth. You may be able to tell I don't entirely know what I'm doing but that seems to be all one needs for noob shading. I put this shader on a Leadwerks box brush and flattened the box to a plane. The blend mode is set to alpha, it's z-sorted and I unchecked "cast shadows" in the material editor.
    I want to make a couple points so you can see some of the thinking behind this shader and adapt it to suit you, so I guess I'll just break this up in sections:
    I have some grasp on this first section (in the vertex stage) and I can't remember how I wound up with it but it's just a variation on the TBN matrix in the Leadwerks parallax shader. The one point I want to make about this section is this line:
        TBN_Matrix[2][2] -= 0.25; //lateral reduction
    Somehow in my experimenting I figured out if you subtract some number from TBN_Matrix[2][2] you reduce the parallax effect at grazing angles. If you crank this up to "1.0" while looking at the box in the material editor you can see that along the sides there is no parallax at all. And this grazing angle is where the trouble comes from in dealing with curved surfaces. That makes this useful if you want to put POM on rolling hills or a curved wall, etc.
            //Parallax tangent/binormal/normal matrix
            mat3 TBN_Matrix;
            TBN_Matrix[0] = ex_tangent*mat3(cameramatrix);
            TBN_Matrix[1] = ex_binormal*mat3(cameramatrix);
            TBN_Matrix[2] = ex_normal*mat3(cameramatrix);
            TBN_Matrix[2][2] -= 0.25; //lateral reduction
            vec3 inversecampos = vec3(camerainversematrix * ex_vertexposition);
            eyevec = vec3(inversecampos) * TBN_Matrix;
     
    The camerainversepos (in the vertex stage) is pretty simple but I have no idea why this works. But the z coordinate establishes the foreground depth in the fog (from camera to fog plane) (*shrug*).
        
            camerainversepos = camerainversematrix * ex_vertexposition;
     
    Fragment stage:
    This next section is the same as it is in the parallax POM shader. The texture coordinates are set up as a vec3. The "for" loop creates several "slices" of the texture which increases in alpha according to the heightmap (z-coord). The slices are "pushed" along according to the eye vector (established in the TBN_matrix) and this is what gives the impression of the overlapping "3D" effect. The bright areas in the height map are pushed more than the dark areas. If the height is greater than the parallaxed_texcoords then break. The second "for" loop smooths out the spaces between these slices and that allows you to get away with a ridiculously small number of parallax_steps (slices) and this is why the parallax shaders look so good without being detrimental to the FPS.
    One thing I want to point out here are these "height" lines. I found that if I start with a vec4(1) and subtract the height, which inverts the texture, and then do a 1-the texture inside the smoothstep - reverting it, it flips something in the parallax. When I then increase the smaller parameter of the smoothstep, it greatly reduces the slippage you get with parallax. If you change "anti_slip" to 0 and then run the game you can see what I mean - particularly if you strafe while looking at the fog. It will slip like crazy. So that's why these lines look so ridiculous. But an anti_slip setting of "0.3" appears to be enough to eradicate the slippage. Further, you can see I wrote the texture out twice in each "for" loop. This  is because I'm scrolling the texture in two opposing directions. By multiplying them you get only the intersections of the two, giving a rippling effect very similar to how the normals create motion in the creek shader (20_creek). The "0.8" in the second height line only offsets the size of that texture slightly so that the two textures never line up exactly, which - in game - looks like a momentary freezing of motion. I also clamped the parallax_depth to between 0.0 and 0.1. 0.1 seemed to be more than I needed but if you end up in a situation where you need more than that you can delete this line (line 57) without any problem.
            //Parallax
            //----------------------------------------------------------------------------
            float height;
            vec2 tex = ex_texcoords0 * fog_tex_size;
            vec3 parallaxed_texcoords0 = vec3(tex, 1.0);
            parallaxed_texcoords0.xy += (time * fog_speed);
            vec3 dir = (-eyevec / eyevec.z)/parallax_steps;
            parallax_depth = clamp(parallax_depth,0.0,0.1);
           dir.xy *= parallax_depth;
           for (int i = 0; i < parallax_steps; i++) {
                parallaxed_texcoords0 += dir;
                height =  vec4(1).r - smoothstep(anti_slip,1,1-texture(texture0, parallaxed_texcoords0.xy + (time * fog_speed)).r);
                height *= vec4(1).r - smoothstep(anti_slip,1,1-texture(texture0, 0.8 * parallaxed_texcoords0.xy - (time * fog_speed*0.5)).r);
                if (parallaxed_texcoords0.z < height) break;
            }
            for (int i = 0; i < parallax_steps; i++) {
                dir *= 0.5;
                if (parallaxed_texcoords0.z < height)
                    parallaxed_texcoords0 -= dir;
                else
                    parallaxed_texcoords0 += dir;
                    height =  vec4(1).r - smoothstep(anti_slip,1,1-texture(texture0, parallaxed_texcoords0.xy + (time * fog_speed)).r);
                    height *= vec4(1).r - smoothstep(anti_slip,1,1-texture(texture0, 0.8 * parallaxed_texcoords0.xy - (time * fog_speed*0.5)).r);
            }
            //-----------------------------------------------------------------------------
    I uncommented this next section because I wasn't sure I wanted it. But the idea here is to affect the opacity of the fog from a distance so that when you're far away it is faded, and when you're close it's normal. You can comment these lines in and then on line 97 multiply this dist by the fog_opacity (inside the parentheses) and see the effect by walking backwards while looking at the fog.
            //Distance
            //float fade_dist = 30.0;
            //float max_fade = 0.8; //0 - 1
            //float dist = 1-clamp(smoothstep(0,1,distance(cameraposition, ex_vertexposition.xyz) / fade_dist),0.0,max_fade);
     
    This next section establishes the outcolor. The parallaxed_texcoords0 already has a texture size variable applied to it, and I needed to do that prior to the "for" loops. But this outcolor really just works to add a little extra detail to the look of the fog and so I added an extra texture size modifier so I could change the size of this texture and get a few more "spots" on the surface of the fog. I established the texture with a time element and a reverse timed texture and added them together. I then clamped down the dark areas of the texture so that the fog is mostly light colors (you don't want dark clouds, really. It's fog). Lastly, I put a fog_hue adjustment and a fog_brightness adjustment like I do almost every time (note the spooky green hue). If you go to the fragData0 line and delete the outcolor.xyz you can see what it looks like without this section and it's cool. But I added this because I wanted a little more. It's preferential.

            //Diffuse
            float col_tex_size = col_tex_size_modifier;
            vec2 col_tex = parallaxed_texcoords0.xy * col_tex_size;
            vec4 outcolor = texture(texture0,col_tex + (time * fog_speed * 0.2));
            outcolor += texture(texture0,0.8 * col_tex - (time * fog_speed * 2.0));
            outcolor.xyz = clamp(outcolor.xyz,0.7,1.0);
            outcolor.xyz *= fog_hue * fog_brightness;
        
    The fog part of this shader is Josh's code from the soft particle shader so I'm not entirely sure how this section works but the shader first grabs the gl_FragCoord.xy/buffersize. The gist of this is that the shader is grabbing the entire screen size? Sort of the idea of a depth buffer is that the shader gets the distance from the camera to the fog plane (foreground depth) and the distance from the camera to the ground behind the plane (background depth) then gets the difference between the foreground and the background. And the effect shows weak or strong depending on this difference. At the end there I added a fog fade - which allows you to adjust this difference. You can see if you place your fog plane in a kind of bowl shape that the alpha border around it fades a lot. If you change this number to a 2, for instance, this alpha border will become much smaller (you don't want that). Lastly I added fog opacity which is pretty self-explanatory. But here you can multiply that fog opacity by the dist from the distance section above if you want the fog to fade out from far away.

            //Screen depth
            vec2 fogcoords = gl_FragCoord.xy / buffersize;
            if (isbackbuffer) fogcoords.y = 1.0 - fogcoords.y;
            float fog_backgrounddepth = depthToPosition(texelFetch(texture11,ivec2(fogcoords*buffersize),0).r,camerarange);
            float fog_foregrounddepth = camerainversepos.z;
            float diff = min((fog_backgrounddepth-fog_foregrounddepth)*fog_fade,fog_opacity); //fog_opacity * dist);
             

     
    Finally I set the fog color and alpha. Again I establish the texture and set some time and speed to the texture coordinates to scroll them and here I just mix them together by 0.5. I then clamp the minimum like before. And for the alpha channel I clamp the fog difference by the parallaxed fog color.r - making the fog difference (diff) the minimum color so that the fog will not only fade by the difference but also by the height. I then add the difference times the height to strengthen the effect (though this could be considered preferential as well).

            //Fog
            vec4 fog_col = texture(texture0,parallaxed_texcoords0.xy + (time * fog_speed));
            vec4 fog_reverse =  texture(texture0, 0.8 * parallaxed_texcoords0.xy - (time * fog_speed * 0.5));
            fog_col = mix(fog_col,fog_reverse,0.5);
            fog_col.xyz = clamp(fog_col.xyz,0.3,1.0);
            fog_col.a = clamp(diff * fog_col.r,diff,1.0) + (diff*height);
     
    Ok so that's about it. If you have questions or comments feel free to drop them below.

    39a_ground fog + parallax.zip
     
  6. havenphillip

    Shaders
    Parallax is a cheap way to add a lot of 3D details to any scene. The less vertices on a mesh the better, because parallax doesn't actually add any geometric information. And it requires only the bare minimum number of vertices to work. That makes it fast. And the effect is believable. All you really need is a heightmap and a dream... It's a lot of fun trying different textures with it, and if I could I'd use it for everything.

    However, there are a few limitations to parallax. The first problem you run into  is that it has trouble with the curve. It works best on a flat plane or a slightly curved surface. I've tried this on boulders and such and there is always a problem somewhere at the grazing angles (see below at the parallax occlusion shader). Secondly, parallax sort of "sinks in" to the texture, so your depth is slightly off, thus when you use this texture on the ground and then put objects on it, you get a slight sense that things are always floating a bit. I've done what I can to reduce this problem and you can get away with using it on floors so long as you are not trying to get extreme parallax depth out of it. POM is awesome, but for floors you may also consider the pixel depth offset shader or the parallax + splat shader.
    Noob tips: I think a good general rule of thumb for using parallax is to think in terms of how far your texture details are meant to stick out. In the case of the bricks you're looking at something like an inch from the surface. In that case you can get away with using the base or the classic parallax. But if your details are meant to stick out further (up to about 5 or 6 inches) then you may want to consider parallax occlusion. You can also improve the speed of your parallax shader by scaling down your normal, specular, and height maps in a 2D image manipulation program such as GIMP of Photoshop because the parallax effect is doing some of the work. And if you're not using a lot of depth, or you're not catching the grazing angles, you can reduce your parallax steps in the shaders for speed.
    So on to the shaders:
    Classic parallax is the first shader in this noob_shader series where we actually do something within the vertex stage of the shader by adding what's called a "TBN matrix," which allows for the texture to shift slightly according to the view angle (see link in shader for more on this). This classic parallax effect should be seen as an extension to the normals because the parallax itself is subtle. I haven't messed with this one much, but since parallax is so cheap this could be used to replace the base shader in many cases to add just a little extra to the scene detail, and I reused this brick texture to imply that connection to the base shader here:

    26_classic parallax.zip
     
    Next we have parallax occlusion (or POM). Parallax occlusion takes parallax to a whole new level. Here we use a different version of the TBN matrix - and one I prefer  - because it allows me to adjust the degree of the effect at the grazing angle. Increase the value in this line below (in the vertex stage of the shader) and the effect will flatten along the sides relative to the view angle, and this allows you to use parallax on more rounded objects. Smooth, rolling hills, for instance. But you may have to go back and adjust the parallax depth after raising this:
        TBN_Matrix[2][2] -= 0.25; //lateral reduction
    POM creates several layers or slices of the texture according to the heightmap and stacks them with a "for" loop, creating a 3D effect down "into" the texture. It then slides these layers around according to the heightmap and the view angle. You may notice that there are still sharp corners and edges on the mesh. This is because the parallax effect doesn't cross those bounds. It's a trick of the eye. Not geometry. Note all the tiny little details you can get in there:

    27_parallax occlusion.zip
     
    Next is my attempt at UE4's pixel depth offset (PDO) using gl_FragDepth in glsl. You can see in the circled area what this shader does. It is essentially the POM but the heightmap is used to overlap objects in the scene which furthers the impression of a non-flat surface...using textures on a flat surface. I haven't tried this on anything but a flat floor but I suspect it will work similarly to the POM shader, so it may work on rolling hills and such. Previous versions of this shader worked fairly well on stuff like that. The rocks overlapping the wall near the bottom are actually just the flat texture. One word of note: the gl_FragDepth affects the plane slightly so when you set objects on this surface manually push them down into it a little bit.

    28_parallax pixel depth offset.zip
     
    Here's a parallax + splat shader. I kind of love this thing. Want to put bullet holes on a stop sign or cracks in the sidewalk for cheap? This is the shader to do that. I sometimes refer to it as the "damage" shader because that's essentially the effect this shader yields. And this is probably the most widely useful of these four because the majority of the surface is at the correct depth. I've tried this with success even on very angled surfaces and it works pretty well even there. Note the bool in the shader. This allows you to "puncture" the mesh or not. Use true for bulletholes and such, or false if you don't want something to go all the way through. Also make  sure your alpha masks are set to something other than DXT1 and you're not using .jpg image format.

    29_parallax + splat.zip
     
    Happy shading!
     
    Next: Simplex Noise...
  7. havenphillip

    Shaders
    Ok so I didn't quite do one shader a week but I got to 52. I wasn't sure I could pull it off but hopefully the shaders are diverse enough to give something to work with for most occasions. I tried to keep the language consistent throughout and organize them sort of from easy to hard. I threw in all kinds of links because I don't know a lot of the technical terminology. I don't know how Ultra is going to be but I get the impression it's not going to be too much different. From what I understand, Ultra uses the PBR model for lighting rather than the Blinn-Phong and it uses Vulkan as its shader language. From what I've seen of Vulkan it doesn't look too much different.
     
    I want to continue here for at least a little while. There are still a few things I want to make. An ocean shader and a snowtracks shader, for instance. I've found that LE4 can do just about anything I can think of, though not perhaps on a large scale, and from what I've heard Ultra is going to be extremely fast so hopefully it will be user-friendly enough (for noobs such as myself) that its users can make some of those open world environments we see in PS4 games and such. "Fastest game engine on the market" [paraphrase] is a bold claim but LE4 turned out to be exactly what it was advertised to be and I'm starting to get those little tingles of excitement the closer it gets to the release date. Leadwerks is legit.
     
    A couple tips: One of the things that helped me a lot in working with shaders was to learn what the errors mean in compile. I ran into a few common ones. Sometimes I would try to multiply a vector3 by a vector4 or some other kind of thing and this doesn't work. Also, you can't put uniforms on the left-hand side of the equation (to the left of the "equal" sign). Sometimes I would forget a semicolon at the end of a line and you'll get an error for the line under that line (that's a tricky one because it's telling you the error is on the NEXT line). Also make sure you declare any variable you introduce, such as "float" or "vec3" etc. Most commonly I would simply get an error because I tried to use something that I didn't declare. Like I'd try something like:
        float mask = texture(texture0,ex_texcoords0).r;
    ...and the compiler would tell me that texture0 doesn't exist  because I forgot to include it in the shader like:
        uniform sampler2D texture0;
     
    Another trick I found useful was to use "discard" in the fragment stage. Sometimes I was able to tell where something was or what something did because I used discard. For instance, try this in any of your shaders:
        If (gl_FragCoord.w < 0.1) discard;
    ...this is a good way of finding out what stuff does.
     
    I'm not entirely sure which direction I should go from here. There are certainly some shaders I still want to do and I'll post them here when I'm done. Ideally I'd be able to do ALL the shaders. But that's a process. But I'm open to ideas and shader ideas. One thing I thought might be cool is to start making little scenes. That would mean I'd need to learn how to do some modeling. I just don't know which program I should get for that.
    Anyway happy shading. See you soon.
     
  8. havenphillip

    Shaders
    According to learnopengl.com PBR - or physically based rendering - is "...a collection of render techniques that are more or less based on the same underlying theory that more closely matches that of the physical world...[it] aims to mimic light in a physically plausible way...[and] generally looks more realistic compared to our original lighting algorithms like Phong an Blinn-Phong...PBR is still nonetheless an approximation of reality...which is why it's not called physical shading, but physically based shading. For a PBR lighting model to be considered physically based, it has to satisfy the following 3 conditions:
    1. Be based on the microfacet surface model.
    2. Be energy conserving.
    3. Use a physically based BRDF."
     
    1. Microfacets:
    The microfacet model is an approach to lighting that treats the surface of all things as if they were covered in microscopic mirrors. When these mirrors (or microfacets) all reflect in the same direction you get a highly reflective effect on the eye. When these mirrors reflect in many different directions you get a scuffed "rough" reflection. Thus every surface is treated as having a roughness/smoothness value or some variation thereof. From learnopengl.com:

     

    2. Energy Conservation:
    From learnopengl.com: "The microfacet approximation employs a form of energy conservation: outgoing light energy should never exceed the incoming light energy (excluding emissive surfaces). Looking at the above image we see the specular reflection area increase, but also its brightness decrease at increasing roughness levels. If the specular intensity were to be the same at each pixel (regardless of the size of the specular shape) the rougher surfaces would emit much more energy, violating the energy conservation principle...An additional subtlety when it comes to reflection and refraction are surfaces that are metallic. Metallic surfaces react different to light compared to non-metallic surfaces (also known as dielectrics). Metallic surfaces follow the same principles of reflection and refraction, but all refracted light gets directly absorbed without scattering. This means metallic surfaces only leave reflected or specular light; metallic surfaces show no diffuse colors."

    3. BRDF:
    "The BRDF, or bidirectional reflective distribution function, is a function that takes as input the incoming (light) direction ωi, the outgoing (view) direction ωo, the surface normal n, and a surface parameter a that represents the microsurface’s roughness. The BRDF approximates how much each individual light ray ωi contributes to the final reflected light of an opaque surface given its material properties. For instance, if the surface has a perfectly smooth surface ( like a mirror) the BRDF function would return 0.0 for all incoming light rays ωi except the one ray that has the same (reflected) angle as the outgoing ray ωo at which the function returns 1.0.
    A BRDF approximates the material’s reflective and refractive properties based on the previously discussed microfacet theory. For a BRDF to be physically plausible it has to respect the law of energy conservation i.e. the sum of reflected light should never exceed the amount of incoming light. Technically, Blinn-Phong is considered a BRDF taking the same ωi and ωo as inputs. However, Blinn-Phong is not considered physically based as it doesn’t adhere to the energy conservation principle. There are several physically based BRDFs out there to approximate the surface’s reaction to light. However, almost all real-time PBR render pipelines use a BRDF known as the Cook-Torrance BRDF."
     
    The learnopengl.com PBR shader uses a lookup texture to get the BRDF (brdflut). This is sometimes referred to as "fake BRDF."  The brdf texture included with the two PBR shaders is considered to be "universal" and need not ever change from material to material. You can just leave it in the specular slot every time. From polycount.com:


     
    As I've tried to do throughout, I've broken down some of these principles into simpler shaders so you can how they can be used on their own.
     
    The learnopengl.com PBR shader uses multiple lights. So here I broke that down into a Blinn-Phong. You can adjust the number of lights you need and add the color and position of each in the shader:

    48_blinn-phong + multiple lights.zip
     
    Here is the "fake BRDF" technique. It's actually really simple but I find this very cool. All you do is create a fresnel (09_fresnel) and exchange the vector 2 texture coordinates of the given texture with it. Something like this:
          vec4 iridescence = texture(texture4,vec2(ndotv,0));
     
    You can readily see how it works and change these textures with anything you want, really:

    49_iridescent.zip
     
    The PBR shader splits the lighting in two ways: diffuse lighting, and specular. It further reduces the specular lighting into two parts: the BRDF, and the IBL specular map. The BRDF is shown above. Here is the second part of it. Note this and the PBR shaders are using something called "equirectangular" textures. There is no need to convert them to cubemaps. If you search for "HDRI's" you can find a lot of these for free on the webz:

    50_windows.zip
     
    The PBR shader uses heightmaps and I wasn't sure if there was one "official" method of getting height information so I made one with parallax and one with tessellation. That ought to cover everything. Parallax:

    51_PBR + parallax occlusion.zip
     
    I included with the above and below shader only the bare essential textures. But you can search for PBR textures and there are a lot of them for free with "do whatever you want with this" kinds of licenses. I included a list of them near the bottom of this post. Here this is shown with a texture from the following collection:
    https://lebedev.gumroad.com/l/ekRhc

    52_PBR + tessellation.zip
     
    I tried to follow the learnopengl.com PBR shader as closely as possible. Some of the ambient light was too dark. I wasn't getting good specular IBL. My roughness at 0 looked funky so I clamped it just slightly. Little tweaks like that. And you can adjust all of it. I'm not sure but I'm almost certain these PBR materials are meant to be Z-sorted. The article said nothing about it but the reason I believe this to be the case is because if they are not then any lights added to the shadowed side of the object look very dulled and the surface doesn't look right. You can see that for yourself. 
     
    There is a bit of an art to using the PBR shader. It's not always a magical production. For instance whether the ao texture is more white or more black will affect the outcome. Not all the PBR materials I downloaded came with ao maps or heightmaps. So you may have to improvise depending on this. The basics, however, are that white areas of the metallic texture will be metallic. Dark areas of the roughness texture will be highly reflective (that's a bit counter-intuitive). You can mess with the black and white textures I added, rearranging them to get different effects.
     
    I added this small number at the end of this line to counter the strong black ambience (as seen in the above picture, which looks just a bit washed-out to me) but you can adjust it (line 201 in the tessellation PBR and line 211 in the parallax PBR):
           Lo += (kD * albedo / PI + spec) * radiance * ndotl + 0.0075;
     
    I also added a flashlight option. Just put the script on the object and drag the player into the slot. But it's rudimentary. I figured someone better at coding may be able to develop it if they want and my goal was to get a flashlight working with the z-sorted materials (what a bizarre little obsession with the flashlight I have).
     
    Here is a list of free PBR sources:
    https://ambientcg.com/
    https://3dtextures.me/
    https://www.cgbookcase.com/
    https://freepbr.com/
    https://www.poliigon.com/search?is_free=true
    https://lebedev.gumroad.com/l/ekRhc
    https://www.artstation.com/deepmind/albums/89651

    PBR + equirectangular photos:
    https://polyhaven.com/
     
    Happy shading!
     
    Next: Outroduction...
  9. havenphillip

    Shaders
    If you liked vertex displacement, you're going to love tessellation. Tessellation is very similar, but incorporates the control and evaluation stages of the shader. The Leadwerks box brush creates a box that has two triangles per face. If you want to use some kind of vertex displacement on it you're going to have a bad time. With tessellation it's different because you are able to subdivide the faces with the shader, so you can use the shader to create more structurally complex models. The control stage in the shader does the subdivision, and the evaluation stage can be thought of as a post-control vertex stage - it just resets everything after tessellation has taken place. This "control" over the number of vertices makes the tessellation shader superior because you can take very simple models and subdivide them to exactly the number of vertices you need without going back and forth between Leadwerks and some modeling program.  You can set it to exactly the number you need.
    You can see here this Leadwerks box in the material editor. It has two triangles per face. I subdivided it by 64. You can see how much detail you can with only two triangles:

     
    You can see that two triangles yields a lot. There is a limit, though. I'm fairly certain 64 is the maximum number of subdivisions you can do, and just like the vertex displacement the size of the object matters because the more space you have between vertices, the less crammed the details are. They get too spread out and the tessellation can't keep up with the smaller details. So if you need more than 64 will allow, you will have to subdivide your model a little bit more before you port it in to Leadwerks.
     
    One thing I want to mention. I added this uncommented line in the vertex stage:
        vec4 modelvertexposition = entitymatrix_ * vec4(vertex_position - vertex_normal * 0.1,1.0);
     
    Notice the above and below picture:

     
    Subtracting the vertex_normal from the vertex_position and multiplying it by some small number allows you to reduce this gap. That's just a little trick I picked up along the way. I still don't know how to close those seams. I think Josh tried to explain it to me once but I'm not a technical guy. I couldn't make sense of it. But just swap that line in instead of the standard modelvertexposition line and adjust the number. But don't go too far in because otherwise your plane will go beneath the surface of the mesh boundary and it will cast shadows on itself. You can disable Cast Shadows in the material editor and that will go away but obviously only do that if you don't want to cast shadows at all.
     
    Here's the noobalyzed Leadwerks tessellation shader. It's a nice little Leadwerks gem:

     
    41_tessellation.zip
    So think of your control stage as "controlling" the subdivisions, and the evaluation stage has the heightmap and the height strength and all the other things you would have put in the vertex stage in a vertex displacement shader.
     
    You can add a time element to your heightmap in the evaluation stage to create a wind effect using textures:

     
    42_sheet in the wind.zip
    The sheet in the wind shader is a bit oddball because I haven't yet figured out how to make it two-sided. The problem is that with a two-sided object the height direction goes the opposite direction. So with this shader you get two sheets instead of one consistent sheet. Maybe it's a modeling problem. I don't know. You can set it to two-sided in the material editor but one of the sides won't react to the flashlight. That kind of thing irks me. It's not enough of a solution for me. But potentially this could be used for clothes or any other thing you want to blow in the wind. If and when I figure it out I'll let you know.
     
    I put the heightmap normals information in the fragment shader from 37_normal from heightmap in both of these shaders. That's what gives the sheet any normals at all. You can sort of see it in the soft shadows in the sheet above. You'll see what I mean if you grab this shader and run it in your game.
     
    Also, one important note:  I usually set my heightmaps to uncompressed in the texture editor. That makes a huge difference. Otherwise you get this weird sort of voxelized look. 
     
    Happy shading!
     
    Next: Geometry...
  10. havenphillip

    Shaders
    Simplistically speaking, you could think of the vertex stage of a shader as the "position" of the object, and the fragment stage as the "color." All you really need is position and color. Vertex displacement manipulates the position to warp or move the object. There are many ways to do it but the whole trick revolves around the ex_vertexposition. You may notice in every model shader you have these two lines in the vertex stage:
       ex_vertexposition = entitymatrix_ * vec4(vertex_position,1.0);
       gl_Position = projectioncameramatrix * ex_vertexposition;
     
    I know from things I've seen around the internet that these two lines are establishing the object in model space and camera space. I don't know much about that but roughly the way I see it the first of these lines establishes what the  ex_vertexposition is, and the second line outputs the ex_vertexposition. So anything you do with the ex_vertexposition between these two lines is "vertex displacement." I have three examples in this post. The first manipulates the ex_vertexposition using sin(time) to create a blowing wind effect. The second uses a texture to displace the vertices. And the third uses the player position to influence the ex_vertexposition.
    But since whatever you do with the ex_vertexposition between these two lines qualifies as vertex displacement, you can relegate it more to the realm of art than science. It's kind of just whatever "looks good." In the first vertex displacement example, if you go into the vertex stage of the shader and find the "wind" section there are these long, obnoxious lines. They yield a pretty convincing wind but they're not set in stone. I think a good rule is that it's only wrong if it looks wrong.

    First, since we're talking about wind, I thought this would be a good place to drop a subsurface scattering shader. It's not true subsurface scattering, but it's a pretty good approximation. Subsurface scattering is that phenomenon that occurs when you put your hand over a flashlight and you can see the light coming through your hand. The light hits the one side of your hand and "scatters" under the surface of your skin, and comes out the other side as a glow.

    Set the shrubbery in the scene and then in the Scene tab/General tab scale it to about 5x5x5. Then walk around it to view it from all sides. You'll see the effect:

    33_subsurface scattering.zip
     
    You may notice your shadows are blocky and not picking up the leaves. Use this shader to fix that by putting it in the "Shadow" slot in the material editor:

    34_leaf shadows.zip
     
    Here's the first vertex displacement shader. The effect occurs in time and I don't know how to make videos yet so I didn't bother making a picture. If you grab this shader you can just see it for yourself. Put the tree in the scene and scale it to something like 7x7x7. By the way, I made the tree and the shrubbery with TreeIt, which is a free program you can download somewhere. It's pretty cool and it makes the process of making trees and stuff much easier once you understand the program:
    35_vertex displacement.zip
     
    Next is a displace by texture shader. You use a simple heightmap in the vertex stage to warp the shape and it yields pretty cool results. A few points to note: vertex displacement warps the shape but it doesn't change the collision information. So don't expect to lay down a plane, slap a displacement shader on it and have an instant terrain (I wish!). Apparently shaders are handled on the GPU and collisions are handled on the CPU, so they don't mix. But you can still make cool looking stuff and there is a broad usefulness to it anywhere you want to add 3d effects. It's slower than parallax because you need the actual vertex count, but it doesn't "slip" the way parallax does and you can use it on complex shapes:

     
    Another thing to note about vertex displacement is that the number of vertices and the space between vertices matters. If you have few vertices and they're far apart you're not going to get much of an effect. See the cube - which has only two triangles per face - compared to the sphere which has a lot of vertices close together:


     
    36_displace by texture.zip
    Another thing to note about this is that the normals don't change with the displacement. You can have a warped plane, but the light reacts to it as if it were still flat.  So in the above shader and here I added a section which creates a normal map from the heightmap. I then just mix the regular normals and the heightmap normals in the normals section of the fragment shader. You can change the resolution line but the range of about 200 - 500 appears to be the sweet spot:

     
    37_normal from heightmap.zip
    Lastly we have the interactive displacement shader, which is pretty cool if not rudimentary. You know how when you're playing a 3rd person game and you run through a bush the bush moves? This is a noob version of that. Set the shader on the shrubbery and then attach the script to the same shrubbery. Then drag the player into the slot. When you run through it moves a bit. You can adjust the interact power and the radius of the effect. No picture:
    38_interactive displacement.zip
     
    Happy shading!
     
    Next: Depth Buffer...
  11. havenphillip

    Shaders
    I don't deal with noise shaders that much but there are a lot of examples on Shadertoy. It has a lot of uses depending on what you want, but very often I see noise being used with raymarching to create 3D scenes. I prefer using textures because I can get what I want out of them and noise is a lot of math (noise shaders can get very large very quickly), but I figured a good shader series ought to have a noise function somewhere.
     
    I got this noise from iq of Shadertoy fame. Just a nice little simplex noise:

    30_noise.zip
     
    You can make a mask out of your noise and mix two textures:

    31_noise mask.zip
     
    Here's a simple hash function:

    32_glitchy console.zip
     
    At this point I've almost got all 52 shaders. I may slow down a bit until I know I can plot the rest of the way. Just want to make sure I've got them right before I post them.
     
    Happy shading!
     
    Next: Vertex Displacement...
     
     
  12. havenphillip

    Shaders
    One of those things I wanted to make - and a big reason I think many people get involved in shaders - is water.  If you've been following along and grabbing these shaders you have now almost all the parts you need to make a basic water plane. If you understand these parts then you can manipulate them to customize your water as you see fit. I'm going to spend a little time in explanation here.
    In making this shader I start with the base shader and add a texture scroll effect on the normals (02_texture scroll). I then duplicate this texture and scroll it in the opposite direction to give the impression of rippling water. I then add a creek direction so they both flow together down river as they criss-cross each other and that gives  the impression of flowing water.
    I add a refraction effect to further the illusion and use the normal.z to adjust the refraction amount. Normal.z sort of intensifies the drama of your normals in terms of depth. Using it with refraction warps the pixels behind the plane to a greater degree. With the refraction effect added you get a nice creek base.
    Here I've added a noobalyzed Leadwerks refraction shader, cutting some of the fat, so to speak , so that it is a bit more palatable to those wanting to learn shaders. Thank God Leadwerks includes a refraction shader because I think that process of working it out would have been ridiculous:

    18_refraction.zip
     
    However, the Leadwerks refraction shader multiplies a camerainversenormalmatrix to the normals, which causes problems when you start trying to add things to it. So I came up with a solution that makes refraction work on the top of a box plane, but not necessarily on any of the sides. If you're making a water plane then that works perfectly, and it's a lot simpler than the above shader. I call it 19_creek base:

    19_creek base.zip
     
    In developing a creek from this, the first thing I did was find the refraction line and multiply it by some color. And then I multiply that by some float to give me control over the brightness of the water color:
        vec4 refraction = texture(texture10, screencoord);
        vec3 water_color = vec3(0.8,1.0,1.0);
        refraction *= vec4(water_color,1.0);
        refraction *= 0.8;
     
    I then add a Phong effect to get a light reflection off the normals. Phong is very similar to Blinn-Phong but is half the size and is eerily similar to a fresnel effect. The difference is that in Blinn-Phong the light moves a bit with the eye. We don't really want that since we're simulating a distant sun lighting the plane.  Under the refraction section I add this:
        //Phong
        vec3 lightvec = normalize(lightposition - projectionmatrix[3].xyz);
        float phong = dot(normal,lightvec);
        phong = pow(phong, 2000);
     
    ... and change the output line to this so I can see what's going on:
       ... fragData0 = mix(vec4(vec3(phong),1.0),refraction,0.5);
     
    You can see above I subtracted the projectionmatrix (ex_vertexposition.xyz also works) from the light position, got the dot product of this light direction and the normals, and multiplied the phong by some power. I use a ridiculously high number to sharpen up the effect. Increase the light position.y to about 8.0 or 10.0 to shine better on the top of the plane and you've got this effect (honestly it looks better in motion):

     
    Next I want to get a reflection so I add a cubemap (14_cubemap reflection) for that:
        //Cubemap
        vec3 eyevec = normalize(ex_vertexposition.xyz - cameraposition);
        vec3 reflection = normalize(reflect(eyevec,normal));
        vec4 cube = texture(texture7,reflection);
     
    The cubemap seemed a little dull to me so I use this trick to quickly increase the contrast in the texture, and you may see this around in some of my shaders:
        float contrast = dot(cube.xyz,vec3(1.0))-0.5;
        cube.xyz *= contrast;
     
    After I have done this I mix the Phong and the Cubemap together so that I can adjust them together. Multiply each by some number to increase their brightnesses and I have a nice - albeit metallic-looking, creek:
        cube = mix(cube*1.5,vec4(vec3(phong),1)*2,0.5);
       ...fragData0 = mix(cube,refraction,0.5);

     
    To resolve this metallic issue I use a fresnel (09_fresnel) to mix the cubemap reflection and the refraction to produce a smooth gradient falloff of transparency to reflectivity according to the camera view of the water. That sounds more complex than it is:
        //Fresnel
        float ndotv = dot(eyevec,normal);
        ndotv = pow(ndotv, 0.55)

        ...fragData0 = mix(cube,refraction,ndotv);
     
    Note that I didn't establish an eyevec in the fresnel because I can reuse the eyevec established in the cubemap reflection. End result:

    20_creek.zip
     
    (The above pictures show the Leadwerks cubemap being used in place of the one I provided and it looks a lot better because there is more going on in the sky).
    Lastly, you can take some of these numbers you've added and make variables of them at the top so they're all together. The water_color, for instance, feels nicer to me when I can put it at the top, open the shader and adjust it right away without having to go find it in the shader.
    So there's a creek, or a basic water. Not that much at all once you're familiar with each of the parts. And if you can understand these parts and how to fit them together you are a true noob shader...er.
    Happy shading!
     
    Next: Masks and Texture Blending...
  13. havenphillip
    Masking is pretty easy and useful for adding some variety to your shaders. Masks are usually just some greyscale image that is turned into a float. In shaders floats have a very broad utility because you can add them just about anywhere. Super useful. And they can be used to blend textures or define areas in your material.
    Adding a mask in code is the same as with any texture. The greyscale quality allows you to use a single channel of that greyscale as a representative of all the channels. For instance the red channel. In code it looks something like:
    float mask = texture(texture5,ex_texcoords0).r;
     
    In blending two textures you need the two textures you want to blend and a third mask texture to blend them by. Once you've established them in the shader you simply do this in the output line:
    fragData0 = mix(outcolor,outcolor2,mask);
     
    That's it. The mix function is pretty much the whole trick. But there are other things you can do. One variation of texture blending is by using an alpha mask in what I believe is referred to as "texture splatting."
    If you set your texture with an alpha channel in your image manipulation program and then in the texture editor set the texture compression to something other than DXT1 you can get an alpha blended texture with a smooth falloff (the alpha wont affect the whole object. Just the texture). Make sure when you're doing this you don't use .jpg image types as jpegs don't carry the alpha channel across. I use .png
    In code that looks like this:
    float mask = texture(texture5,ex_texcoords0).a;
     
    Note I used ".a" at the end to signify the alpha channel. Here's a nice moldy example of that:

    21_texture splat.zip
     
    Below is your standard two-color blend. It gets a little tricky adding the normals. I think in this one I just did the entire normals section twice but it just comes down to mixing the normals by the mask so I believe you could get away with something like this:
        vec3 normal = ex_normal;
        normal = normalize(texture(texture1,ex_texcoords0).xyz * 2.0 - 1.0);
        vec3 normal2 = normalize(texture(texture6,ex_texcoords0).xyz * 2.0 - 1.0);
        normal = mix(normal,normal2,mask);
        normal = ex_tangent * normal.x + ex_binormal * normal.y + ex_normal * normal.z;    
        normal = normalize(normal);

    22_two-color blend.zip
     
    This three-color mask actually uses an rgb mask rather than a greyscale. The shader looks exhausting but really I'm just doing the same thing over again three times - once for each color. You may notice on the right  there that I ran out of spaces so I just use a generic method for the specular. It's kind of cool you can just change where the colors show by changing the mask. Make sure in making masks for this that you use really really blue, really really red, and really really green otherwise your textures will blend into areas you don't want them:

    23_three-color blend.zip
     
    Here  I used a cubemap to get some reflective little puddles in the mix and mixed the specular and normals by the mask without changing the diffuse:

    24_bepuddled terrain.zip
     
    This one doesn't even use a mask but I think it's cool. It uses "normal.y" as a means of mixing textures. So if you want to add snow to the top of a rock, for instance, you can use this shader to do so. The blend settings are adjustable:

    25_slope blend.zip
     
    Open your two-color blend shader and find the "float mask =.." line around line 54 and change it to " float mask = 1.0-normal.y; " ("1.0 - something " just inverts the thing), compile (press the "play" button on the Script Editor), and watch what happens. Or change that line to " float mask = gl_FragCoord.w + 0.35; " and check that out. Once you figure out your float you can pretty much mix your textures by anything.
    Happy shading!
     
    Next: Parallax
     
     
     
  14. havenphillip

    Shaders
    If you took a bowl full of water and looked straight down into the bowl, the water would be clear. But if you were to then move the bowl up to your eye and look from the side along the surface of the water, you'd see it becomes highly reflective. That's fresnel.

    It's a cool effect. And it's easy to code. You add a uniform vec3 cameraposition towards the top and a fresnel color, and then a fresnel effect is little more than this:

    vec3 eyevec = normalize(cameraposition - ex_vertexposition.xyz);
    float ndotv = dot(normal,eyevec);

    After that all you need to do is output it. I put it in the specular output (fragData2). But you can put it in the the diffuse output as well. You just mix these two colors by the fresnel effect (or the 1.0-fresnel effect):

    fragData0 = mix(outcolor,fresnel color,ndotv);

    ...and there it is. Effects like this are nice because you can just keep tweaking them to make different things:

    09_fresnel.zip
     
    So if fresnel is a step up from the base shader, blinn-phong seems to me like a logical second step. Blinn-phong puts a "dot" on an object which simulates a light. I find this useful in particular if you want to z-sort a material to gain semi-transparency. For instance, glass. The problem is once you z-sort it you lose specular information. So you can add a blinn-phong to your object and maintain specular. You can also adjust the size of the dot to give the impression of "shininess" like you can with specular. But one thing you can do quite easily with this is change the color of the light. Later I would like to write a shader that allows for multiple blinn-phong lights. I haven't gotten around to it.
    So in the fresnel you established the normalized difference between the cameraposition (eye) and the object position(ex_vertexposition). With blinn-phong you also want to establish the normalized difference between the object position and a light source (projectionmatrix). You then add the fresnel to this, get your dot product just like in the fresnel, and then mix this into an output line (fragDatasomething).
    Blinn-Phong:

    10_blinn-phong.zip
     
    If you stagger the light falloff in the blinn-phong you can create a toon lighting effect:

    11_toon lighting.zip
     
    Here you have two colors mixed by a fresnel effect to create a pearl effect:

    12_pearl.zip
    Here's a blinn-phong with alpha:

    13_blinn-phong + alpha.zip
     
    Next: Skybox Reflections...
  15. havenphillip

    Shaders
    Another simple shader technique is the skybox (or cubemap) reflection. Cubemaps are useful for creating quick and easy reflective surfaces for objects and work particularly well on curved surfaces or objects with bumpy normals. You can create an impression of a metallic, wet, or polished look quite easily (provided you have a way to generate cubemaps). In code, they are about as easy as fresnel, which gives them something of a broad utiity. Once you have the technique, you can treat it as a "part" to add to other shaders.
    Here's the cubemap section in the shader:
        vec3 eyevec = normalize(ex_vertexposition.xyz - cameraposition);
        vec3 reflection = normalize(reflect(eyevec, normal));
        vec4 cube = texture(texture7,reflection);
    Not much at all.
    Below is my noob skybox reflection shader. Note the vec3 effect is put in "fragData2" which handles specular and emission. Basic noob specular output can be written like this "fragData2 = vec4(0,0,0,1); Technically, it is only the alpha channel in the output which handles the specular. The ".xyz" of the output handles emission. So anything you put there will become emissive, like a light. Try fragData2  like something like this: "fragData2 = vec4(1,0,0,1); Now your shader glows red and you've learned emission in shaders - you shader artist, you:

    14_skybox reflection.zip
     
    Add a fresnel to a skybox reflection and you get a metallic chrome effect:

    15_metal.zip
     
    I used a little contrast trick I learned from the desaturation shader and created a specular reflectance effect using a cubemap and a blinn-phong. It yields a polished look like wet or waxed paint:

    16_polished.zip
     
    Below I combined the fresnel, blinn-phong and cubemap reflection to revisit the pearl shader.
    As you can see, for the most part, shaders are just a lot of smaller parts combined to produce some effect. it's a lot of mixing and matching. But once you have those parts you can reuse them to your heart's content. It is my goal that by the end of this series I will have given enough of these parts that those wanting to learn shaders can do just about anything they can think of, and if I succeed getting one guy up that initial step then this endeavor has been a success.
    Happy shading!
     

    17_pearl revisited.zip
     
    Next: Creek...
  16. havenphillip

    Shaders
    Here's some more extra shaders. I had a lot of fun with these. Some playing with normals. Some post-effects. Some experimental stuff. Just a mixed batch of noob adventures.
     
    This first shader is pretty simple and is a nice noob move to add more detail to any scene. You start with the base shader and simply mix it with another normal texture. You can easily see the effect it produces and this is useful if you want to add small details to a material - like for instance making skin or rocks (below) more porous, or if you want to show the threads in a cloth, etc. It's a cool little effect to have in the repertoire and it only requires an extra texture and two extra lines of code in the normals section:
        //Normal
        vec3 normal = ex_normal;
        normal = normalize(texture(texture1,ex_texcoords0).xyz * 2.0 - 1.0);
        vec3 normal_detail = normalize(texture(texture4,ex_texcoords0 * normal_detail_size).xyz * 2.0 - 1.0); <-- here
        normal = mix(normal,normal_detail + normal, normal_detail_mix); <-- here
        normal = ex_tangent * normal.x + ex_binormal * normal.y + ex_normal * normal.z;    
        normal = normalize(normal);

     

    00a_normal detail.zip
     
    This is a variation of the normals from heightmap shader (37_normals from heightmap) and I included it because I'm getting some better results with it than the other one. Set the heightmap to uncompressed in the texture editor for best results. You can see the normal dot3 map created in Leadwerks from the diffuse gives a nice normal map but it's not very bumpy. The "super bump" shader yields way more dramatic (and rounded) results, but you lose a bit of the sharp details that you would get from something like the Leadwerks normal because you are basing the normals on the heightmap. You can adjust the resolution to get varying results with 1000 being sharp but not very rounded normals. The picture below has the resolution set to about 300. The technique from the normal detail shader above is included so that you can still use the regular normal map to add details to the normals or double down on the normals in order to get some of those little details back. The difference here is instead of using two normal maps you're using one normal map and one  (adjustable) heightmap. I love this thing. It really adds a lot of drama to your materials:

    37b_super bump.zip
     
    I thought a shader collection ought to have an anisotropic specular and this was a pain to get working. You can see in the code it just looks like a tangled blinn-phong mess but it looks cool and can be used to give that anisotropic look to hair (below) or brushed metal.

    48b anisotropic specular.zip
     
    This next shader does a texture scroll on a normal texture and then adds the xy of that texture to the texture coordinates of the diffuse:
        ...water_normal = normalize(texture(texture6,water_texsize * tex - vec2(0,time * speed)).xyz * 2.0 - 1.0);
       ...vec4 wet_diffuse = texture(texture0, tex + (water_normal.xy * 0.1));
       ...fragData0 = mix(outcolor,wet_diffuse,mask);
    This produces sort of a wobbling pseudo-refraction effect in the diffuse by slightly shifting the texcoords of the diffuse according to that scrolling normal, which gives the effect of water running down the face of a surface. Add a cubemap for reflections and a mask and you get this effect:

    22a_weeper.zip
     
    Here is a high-pass filter shader I made from the kernels blur shader. The high-pass filter is easy to create in Photoshop or GIMP. Essentially what you're doing with a high-pass filter is using a blur to sharpen an image. The idea is that you take the diffuse texture and blend it with a blurred and inverted version of itself. When you do that, you get just a grey image, but the blurring slightly offsets one of the textures and the difference created really dramatically draws out the little details in the image. I included a post-effect version of this here and I believe that would be the correct use of it, as seen below:

    01d_high pass filter.zip
     
    This is my attempt at creating a waterfall. I thought the tessellation shader would be a solid direction to go in and it did turn out pretty good. The trick was to get the diffuse texture scrolling with itself. Once I got something that looked pretty decent I copied and pasted that outcolor section into the evaluation stage as the displacement so that the lighter colors would jut out more than the darker colors - so there is a consistency in color and displacement. The material is z-sorted to get the alpha fade and as a result I lost the specular. So I used a blinn-phong to get a light source and then scrolled the normals so that I could get those little "sparkles" which is consistent with water effects. Ultimately all the scrolling speeds and texture sizing are pretty arbitrary. I was just trying to make chaos that looked cool and gave me the impression of falling water. My modeling skills are not that great and I get the feeling this shader could look much cooler with a better model, but the effect is there. One thing to note is that when I made the model I uv-mapped the mask to it so that it would fit regardless of the size or how I might stretch the Y scale on the model to make it taller or shorter, and the mask fades to black (alpha) near the bottom. On taller waterfalls this gives the impression that the water is dissipating into mist:

     

     
     

    41b_waterfall.zip
     
    This last one is just a fun experiment I was messing with. There are techniques for turning a diffuse image into an albedo image in Photoshop or GiMP using the Luminance/Luminosity blend mode. The reason you would do that is  because you don't want shadow information in your diffuse texture. You want only color and you want the shadows and highlights work to be done by the lighting, object shape, and normals. The idea behind this shader is that you take the diffuse texture twice (one being the blend and one being the base) and blend these by the luminance so that the color of the blend blends according to the luminosity of the base (or was it the other way around???). This shader simulates that technique (There's a video link I included at the top of the shader that explains it better). You can adjust the contrast and saturation, and I included a post-effect version of it so you can "albedoize" everything all at once - and I have no idea if that's something that should actually be done but it was fun for me (You could maybe treat it as a tone map or something). You can see it colors in the dark areas and sort of flattens out the contrast. I set the diffuse and height textures to uncompressed and it looks pretty good:

     

    53_albedoize.zip
     
  17. havenphillip

    Shaders
    Note: In my last post shaders 36 and 37 weren't working correctly so I replaced them. If you got the old ones you can throw those out and re-download the new ones on the same links.
    These shaders are based on the Leadwerks soft  particle shader, which I was directed to by Marcousik, and which I noobalyzed into a model shader. What the soft particle shader does is create a soft falloff in opacity depending on how close objects are behind it. To clarify, imagine looking down at a water plane, and a terrain beneath it. Depending on how far away the terrain is from the water plane determines how much of the effect you see. If the water plane is near the ground along the shore it is invisible. But on the deep end, where the ground and the water surface are far apart you get more opacity in the effect.
    The core of what's going on is you're getting the distance from the eye or camera to the water plane, and the distance from the eye to the terrain surface, and then you're finding the difference between the two.

    This shader makes nice fog effects. Just make a plane and set the shader on it, and adjust the height to your liking:

    39_ground fog.zip
     
    If you invert the effect using  "1-diff" you get a strong opacity near objects which then fades to alpha the more space there is between its surface and the surface behind it. That's how I was able to make this forcefield shader:

    40_forcefield.zip
     
    Happy shading!
     
    Next: Tessellation...
     
×
×
  • Create New...