Okay, let's unpack this. Today we're taking a deep dive into the fascinating world of game visuals. We're going to pull back the curtain on how developers craft those stunning, immersive graphics you see in modern Unity three D games.
Right.
Our mission isn't to bury you in technical jargon, but to cut through the complexity and extract the most important nuggets of knowledge and insight. Yeah, make it accessible, and we're drawing heavily from a truly fantastic resource, the Unity Shaders and Affects Cookbook by Kenny Lammers. A book that's well, it's a masterclass in practical recipe based learning, and it's full of surprising facts.
That's right. This deep dive is your shortcut to being well informed about the magic behind how games look. Think of it as unveiling the clever illusions and powerful tools that turn polygons into vibrant living worlds.
Yeah.
We'll explore everything from the kind of foundational building blocks of visual effects to advance techniques that make a game truly shine. Our goal is to help you understand not just what shaders and effects are, but why they matter to the final esthetic and performance of a game. And how they contribute to that wow factor.
So we're talking about making things look good in Unity. When you're building a game, where do you even begin to well paint that visual masterpiece?
We begin with shaders. Imagine them as tiny, highly specialized painters that live inside your graphics card. Well painters, Yeah, exactly. Every surface in your game, a tree, a wall, a character skin gets painted by a shader. Historically it was like using a preset brush, maybe a bit rigid, But today, with modern rendering languages like Craig and Unity's user friendly surface shaders, developers have vastly more.
Control, more flexibility, way more.
Unity surface shadors are particularly efficient because they handle a lot of the heavy lifting for the graphics processing unit, the GPU, making it much smoother to customize how things look.
That sounds incredibly powerful. So we're building these custom painters, these shaders, But how do artists who might not write code actually use them? Is there a simple way to tweak things?
Absolutely? That's where properties come in. Think of them as the adjustable knobs and sliders on your shader's control panel right in the Unity editor.
Ah okay, so the artist sees those directly.
Yep, they let artists or designers fine tune colors, textures, or how shiny something is directly within Unity's inspector tab. No coding required for them at that point.
That makes so much sense. So these properties literally let you declare different kinds of inputs. You could have a color property for a color picker.
Maybe exactly, or a range for a slider. You can have a two D property for a texture image, a cube for something called a cube map. We'll definitely get to those later, okay. Or simple float values for numbers. Eat property like a missive color or my slider value links directly to the shader's inner workings. And the real beauty here is you can set up a slider in the Unity editor that, when dragged, might dynamically change how sack traded a color is in your game, all in real time. Wow.
Yeah, that must be a huge time saver. Empowers the artists directly. What's fascinating here is how textures then become more than just image files you said, They become powerful data containers.
Indeed, think of a texture not just as a pretty picture, but as a candice where each pixel can hold different kinds of information.
It's quite clever like scrolling textures for effects like waterfalls, rivers, or maybe lava flows.
Exactly, it's an illusion of movement, but incredibly effective. You're simply shifting the textures, coordinates, the uvs over time in the shader, often using unities built in time variable.
Just sliding the picture along basically pretty much.
And similarly animating sprite sheets. People often call them sprite atlases. That's like creating a digital flip book.
Ah.
You're taking a large texture with many smaller images frames of an animation, and the shader cleverly cycles through them, using precise mathematical calculations like wad and seal to create that smooth illusion to movement.
And here's an AHA moment, I think, especially for performance packing textures. You mentioned storing multiple grayscale images inside a single texture.
Yes, like a secret compartment. You use the red, green, blue, and alpha channels, the RGBA channels to store four different grayscale maps.
Why is that so important?
Memory textures eat up memory, especially on mobile. Packing them like this drastically shrinks your app size. It's a huge optimization.
Okay, so you pack them save memory, then.
What then the shader can intelligently blend these hidden images together on a surface. You use the LURP function linear interpolation to smoothly transition between say, grass, dirt, and rock on a terrain model, all from one tiny file.
That sounds incredibly useful for detailed environments it is.
And then there's normal mapping. This was well a truly genius technique that let games leak forward visually without tanking performance.
Right, making things look bumpy without adding actual polygons.
Instead of requiring complex high polling models. A normal map uses a special texture where pixel colors represent surface direction. It tells the light how to bounce off, faking intricate detail on a.
Low poly mesh like optical illusion geometry kind of.
Unity even has helpers like unpack normal to make it easier, and you can control the intensity with a shader property like a normal map intensity slider.
It doesn't stop there, though. What if you need patterns that aren't in a file, or need to adjust textures on the fly.
Well, you can create procedural textures dynamically within the Unity editor using c sharp.
Scripts, generating them with code.
Yeah, you can generate patterns, shapes, maybe gradulate distances to create rings or gradients. You can even replicate Photoshop levels effects directly in your.
Shader, like adjusting brightness and contrast in real.
Time exactly adjust brightness contrast gamma using functions like max to clamp values. Precise artistic control, but generated dynamically.
Okay, so we've painted surfaces use textures as smart data. But what about making things really shine and reflect the world around them that metallic glint or waterychine.
Right, That's where specularity comes in. It describes how shiny an object is, and crucially, it's a view dependent.
Defect, meaning it changes based on where I'm standing.
Precisely the highlight moves as you move around the object. A core concept here is the half vector, which is sort of an efficient way to calculate where that highlight should be between the light source and your viewpoint. Unity provides a built in blind fong lighting model that's very common and pretty efficient for this.
But you're not limited to just the built in options, right? Can artists get more granular control?
Oh? Absolutely not limited. You can write your own custom shine models and masking specula with textures gives artists incredible pixel level control.
So using a texture as a stencil for shininess.
Exactly a grayscale texture, where black means matt and white means full shine. This leads to tech niques for simulating different material properties, think metallic versus soft speculat.
Like brushed metal versus say, plastic.
Precisely, you can mimic different roughness levels or even at a fresnel term. That's the effect where reflections get stronger at glancing angles, like on water or car paint. And for really specialized surfaces like brush metal or even hair, there's anisotropic speculator that uses a normal map not just for bumps, but to define the direction of the highlight, making it stretch along the grain usually needs a slightly more powerful shader model like three.
Point zero reflections. Then, equally important for realism, how do we get objects to actually mirror their surroundings.
The key there is cube maps. Remember the cube property type.
Yeah, you mentioned we'd get back to those right.
So imagine taking six photos up, down, left, right, forward, backward, all from one point, stitch them together into a cube. That's your cube map. It captures the entire environment around an.
Object, like wrapping the object in a photo box.
Pretty much, you can create cube maps directly in Unity, using a function called rendered a cube map, often with a little menator helper tool for static scenes, or use external tools like Ati cube map gen for more control.
Okay, so you've got your environment, box, your cube map. How does the shader use it?
Unity makes simple cube map reflection surprisingly easy. The shader's input data usually have a built in vector, often called world refle that automatically calculates the correct reflection direction based on the surface normal and view angle.
So it knows where to look into the cube exactly.
Then you just use the text key function to sample that cube map at that direction and boom you get the reflection color.
And just like with speculator, I assume you can control where it reflects.
Yep, you can mask reflections using another grayscale texture black for no reflection, white for full reflection, same principle.
And combining normal maps with reflections for bumpy reflective surfaces.
Absolutely, That's where it gets really convincing. You need to access the surface normal after it's been modified by the normal map. Unity provides ways to do this, often using something called internal data. Then you use a function like world reflection vector to calculate the reflection direction based on that bumpy normal the reflection gets realistically perturbed.
Makes sense, So the bumps distort the reflection, right, And.
You mentioned fresnel reflections earlier with specularity, same applies here, very common for making reflections pomp at glancing angles looks great on water glass car paint.
And can these reflections be dynamic update in real time?
They can, but it's computationally expensive. You can build dynamic cube map systems that maybe swap between precaptured cube maps based on where the object is, or even re render the cube map periodically in real time.
So needs careful scripting. Maybe checking distances.
Exactly use c sharp scripts, maybe with execute an edit mode for editor previews, check distances using vector three, do distance and trigger cube map updates or swamps. It's powerful, but needs optimization. So if we connect this to the bigger picture, beyond the fundamental shine and color from diffuse in speculator lighting, custom lighting models let you achieve incredible visual fidelity, especially for really complex or unique surfaces, things that standard lighting just doesn't capture.
Well, what's one of the more maybe unconventional approaches to lighting. You see something that doesn't rely on standard lights in the scene.
One really interesting one is the lits sphere lighting model. You might hear it called Matt caps, especially if you've.
Used z brush Matt caps. Okay, how does that work.
It's a form of image based lighting. Basically, the entire lighting and shading of an object, highlights, shadows, everything is baked into a single two D texture, which looks like a picture of a sphere lit in a certain way.
So you map that sphere image onto your object sort of.
Yeah. The shader uses the object surface normal relative to the camera to look up the color on this sphere map. The big catches. This lighting is completely fake in a way. It doesn't react to scene lights at all.
Ah, so it's always lit the same way relative to.
The camera, exactly locked to the camera's view. But you can swap out the Matt cab texture to instantly change the perceived lighting and material. It's very fast, great for stylized looks or sculpting previews.
Interesting shortcut. What else in image based lighting?
Another technique is the diffuse convolution lighting model. This uses a preprocess sort of blurred cube map to simulate soft diffuse ambient lighting from the environment.
So capturing the general color of the surroundings precisely.
It gives you that nice effect where an object picks up ambient color from say a blue sky above and green grass below. I think ambient cube shading a convolution or blurring process is too slow for real time, but you pre calculate it great for static scenes or cinematics. For that realistic environmental downslid. It often uses the world normal vector function to sample this blurred cube map.
Okay, so you have these specialized models, but then you start combining things. Right, what's a good example of a material that pulls multiple techniques together.
The vehicle paint lighting model is a perfect example. It's not just one simple effect. It's often a sophisticated blend. You might use special BRDF textures B or bidirectional reflectance distribution function basically textures that define how light reflects differently based on viewing and light angles. So you use those for the diffuse color, maybe get that subtle color shift you see on cars, and you combine it with cue
AAPS for the sharp clearcoat reflections. It really brings many techniques.
Together, right, that complex layered Look what about something really organic like skin that seems incredibly hard to get right.
Oh. Skin shading is notoriously tricky because light doesn't just bounce off skin, It penetrates and scatters underneath, called subsurface scattering.
How do shaders even fake that?
Well? The diffuse part often uses a BRDF lookup texture specifically designed to simulate that light scattering, and the speculator or shine is complex too. It usually incorporates fresmal effects and maybe some rim lighting techniques to give that soft, waxy highlight you see on skin. It often relies on calculating things like blurred normals and surface curvature.
Curvature like how quickly the surface is bending.
Yeah, Using functions like fwidth to find sharp changes in length to measure how sharp they are helps find details like pores or wrinkles to subtly affect the lighting.
Wow. And for cloth shading, getting that fabric look a.
Common technique there involves detail normal maps and detailed textures.
Using two normal maps.
Yeah, you overlay a fine tiling normal map representing the weave pattern on top of the main normal map for the folds. This achieves a higher level of micro detail, helping to break up and realistically disperse the speculator highlights across the tiny fibers makes it look much more like actual fabric.
We've covered a lot on making things look solid, shiny, reflective, but what about the opposite, making things see through? Transparency seems simple, maybe just an alpha channel, but you mention it causes issues.
It does, especially with draw order. Creating transparency with alpha is the fundamental part. Yes, you add an alpha parameters your shadeer's set up the hashtag pragma statement telling unity it can be transparent. Then you feed a value, usually from a texture's alpha channel to the O alpha parameter in your output. Zero is fully transparent, one is opaque.
Okay, standard stuff. But then there's the transparent cutoff shader. How's that different?
Right? Cutoff uses an alpha test variable name parameter. Instead of blending smoothly, it acts like a switch. If the alpha value is below a certain threshold the variable name the pixel is completely discarded, fully transparent. If it's above, it's fully opaque, no in between grays.
Why use that performance often?
Yes, especially historically, it avoids some blending complexities. But counterintuitively, the source points out that on some mobile GPUs, doing that per pixel test for the cutoff can actually be more expensive than regular alpha blending depends on the hardware architecture.
Huh. Interesting, So this draw order problem, how does Unity handle stacks of transparent things.
That's where depth sorting with rendered cues comes in. Normally, a Unity draw solid objects from front to back using the depth buffer or Z buffer to make sure closer things cover farther things. Transparent objects are usually drawn after solid ones sorted back to front, back to front. Why so that you can see farther transparent objects through closer ones correctly. But you can override this default sorting using
tags in your shader. You can set tags q transparent ten, for example, to force an object into a specific drawing order within the transparent group.
So you can layer them manually if needed.
Exactly. Unity has built in queues like background geometry, alpha test, or cutoff shaders transparent and overlay, and a crucial tag for transparent objects is z write off. This tells Unity not to write the object's depth information into the depth buffer, which is essential for letting things behind it render correctly.
Okay, that makes sense. So a practical example maybe GUI and transparency like three D interfaces floating in the world.
Perfect example, you might create a cool three dui using texture sheets with alpha channels for buttons or readouts. When those UI elements get very close together, maybe overlapping slightly, Unity's automatic sorting might flicker or get confused.
Right, you see that Z fighting sometimes exactly.
So this is where a small C sharp script, maybe using execute and edit mode so it runs in the editor, becomes invaluable. It can let you dynamically adjust the Q values for individual UI materials right there in the inspector. It gives you that fine grained Photoshop like layer control over your three DUI.
Elements, super useful for complex interfaces. Now, moving beyond just surface appearance. Vertex magic, you mean, shaders can actually change the shape of the model precisely.
There's a special function within a shader, the vertex function, that runs once for every single point or vertex that makes up the three D model. Inside this function, you can manipulate that vertex's position, it's color, even it's textra coordinates uves before it even gets rendered.
WHOA, so you can access a vertex color in a surface shader. Models can store colored data per point.
They can often export of and three D modeling software. You can retrieve this using a specific infesststructure like ap data full and passed along. This float for color variable can hold RGB and even an alpha value for extra data right there on the vertex.
What can you do with that vertex data?
All sorts of cool stuff. You can animate vertices in a surface shader. Imagine making a flag ripple realistically. Instead of complex bones and skinning, you just apply a sine wave using the sin function to the vertex positions based on time.
So the shader itself makes the flagwave.
Yeah, or create ocean waves pulsating effects, all without traditional animation systems. You could also use Vertex color for terrains to blend textures. For instance, paint Vertex colors onto your terrain mash, maybe red for rock, green for grass, and use those colors in the shader to control the blend. Combined with a height map, this lets you get really detailed blending in crevasses and on hillsides. Games like Uncharted in Gears of War made this popular for their stunning environments.
This all sounds incredibly powerful, but it does raise important question. With all these techniques layering effects, maybe animating vertices, how do we keep things running smoothly? Especially on say, mobile devices, How do we manage performance?
That's the critical question, isn't it? What makes a shader cheap or efficient? It's not always obvious.
It's not, but generally it means optimizing a few things, minimizing memory usage for variables, keeping the number of texture lookups low, and writing efficient code logic within the shader itself, fewer calculations per pixel.
Basically, how do you even measure that? How do you know if a shader is slow?
Unity's built in profiler is your absolute best friend here. It's like an EKG for your game.
Okay.
Lets you track GPU usage, CPU usage and specifically rendering performance. Frame by frame. You can see details like draw calls, how many separate things are being drawn, and the actual milliseconds.
Spent rendering, so you can pinpoint bottlenecks exactly.
Profiling might clearly show that adding just one more texture lookup and ALERP function for blending significantly increases the render time for certain objects, guiding you directly to where optimization is needed.
And what about specifically modifying shaders for mobile? Are there common tricks?
Yeah? There are definitely mobile specific considerations. You might use simplified lighting functions like a proxview or half as view, which are faster but slightly less accurate. You might declare variables using fixed or half precision instead of full float to save memory.
And bandwidth smaller numbers basically right.
You might also use directives like no forward ad to limit complex per pixel lighting to only one directional light, significantly cutting down calculations, or explicitly state no light mapping support if you're not using baked lighting to prevent the shader from doing unnecessary checks. Yeah, it's always a trade off. Balancing visual fidelity with the performance constraints of your target hardware makes sense.
It sounds like you could end up with lots of slightly different versions of shaders, though, how do you manage that complexity.
That's where modularity comes in. Making your shader world modular with c includes is crucial. Think of them like shared code libraries or header files and C plus plus hand. Unity already provides several built in siege include files. Unity CG dot c jink is a big one, full of helper functions for common tasks like calculating luminance for desaturation effects lighting. Dot cjinc defines the standard built in lighting models like blindphone.
But the real power is making your own.
Absolutely you can create your own cg include files, dot caging files. You wrap your custom lighting models, helper functions, maybe common variable declarations inside preprocessor directives like hashtag, if def hashtag define and hashtag NF.
So you define a block of code once and.
Then you just hashtag include my customs stuff, dot cgenejink at the top of any shader that needs it. It keeps your shaders clean, avoids repetition, and makes updates much easier, super efficient workflow.
That sounds way better than copying and pasting code everywhere.
Oh it is. And you can even use hashtag defined directives within your main shaders to build shaders with multiple states or feet feat How does that work? You could write your lighting code inside and hashtag if stiff my cool feature hashtag end off block. Then maybe in your material inspector or via script, you can enable or disable that hashtag define. Unity shader compiler will then create different compiled versions, one with the feature, one without, all from
the same source file. Immense flexibility without managing dozens of near identical shader files.
Okay, that's really clever for managing variations So we've built our objects, lit them, maybe made them transparent or wavy, But what about that final polish, that cinematic look. How do artists tweak the entire screen image?
Ah? Now you're talking about screen effects, often called post effects or post processing. This is where the real magic often happens for mood and.
Style, So effects applied after everything else is drawn.
Exactly, you grab the entire rendered image of your game just before it's shown, process all its pixels on the GPU using another shader, a post effect shader, and then slap that altered image back onto the screen. It's like having photoshop layers and filters running over your live game view.
How do you set that up? In Unity?
It typically involves the script system. You attach a c sharp script to your camera. That script uses unities on render image function, which gets called after the scene is rendered. Inside that function, you use graphics dot blit. This takes the source render texture the current screen image, passes it to your post effects shader. The shader does its magic in its frag function fragment function, and blit puts the
result back onto the screen. Usually requires Unity pro or now it's often part of the Universal render pipeline or high definition render pipeline features.
Okay, so you have this pipeline, what kind of things can you easily do? Basic color correction?
Absolutely, you can easily control global brightness, saturation, and contrast a function in your shad maybe contrast saturation brightness can adjust these values. Brightness calculation often uses standard luminance COEFT values based on how humanized perceive color, and you use LERP functions to blend between the original and adjusted color smoothly.
What about those basic Photoshop like blend mode like multiply.
Or screen yep, totally doable. Multiply is simple. Just multiply the pixel color from the render texture with the color from another blend texture. Channel by channel darkens the image add sums them, brightening it. Screen blend is a bit more math. Invert both textures, multiply them, then invert the result again. Gives a nice brightening effect that preserves whites. Each one is just a precise mathematical formula applied per pixel.
And what about a more complex one like overlay blend mode?
That was cool? It uses conditional checks for each pixel and color channel. It checks if the blend texture's value is less than point five. If it is, it applies a formula similar to multiply. If it's greater than or equal to point five, it applies a formula similar to screen. It creates a nice contrasty blend that preserves mid tones. Again just math, but give sophisticated artistic.
Control beyond just global adjustments. How are these screen effects used for gameplay and screen effects to really enhance immersion? Oh?
All the time. These effects can be triggered by in game events to dramatically change the mood, signal, danger, simulate conditions. It's huge for immersion.
Like what give me an example.
Okay, take the old movie screen effect. That's not just turning a grayscale. That's a combination of effects.
Right, needs more than just desaturation.
Yeah, you'd add a cpio tone for that brownish vintage look. You'd add a vignette effect, darkening the corners and edges like lightfall off from an old projector bulb. And crucially, you'd overlay animated dust and scratches textures animated. Ah, you scroll the uvs for the dust scratch texture over time, maybe using unity sind time or just time, and maybe add a random value multiplied in to make it flicker
or jump slightly, simulating film imperfections. The cpiotone often uses specific YIQ color space values for accurate luminance calculation before tinting.
That sounds really convincing. What about another classic like night vision?
Ah, yeah, the staple of many first person shooters. That's another combo of effect. You need that distinct tinted green overlay obviously, but then you add scan lines, faint horizontal lines. You add some noise or grain to simulate the sensor noise. You definitely add vignette, often quite strong, simulating looking through a circular scope. And for extra polish, maybe some lens distortion.
Lens distortion like Fishie.
A little bit. Yeah, using functions like barrel distortion to slightly curve the edges of the screen outwards. It all comes together to sell the effect of looking through a device, not just seeing a green screen changes your whole perception.
Wow. Okay, So from the absolute basics of surface shaders and the power of making things adjustable with properties.
Yeah, all the way to transforming textures into data, faking detail, making things shine.
Creating dynamic reflections that really mirror the world, even bending and animating the models themselves with Vertex Magic.
Right through optimizing for different platforms, making your code reusable with includes.
And finally layering on those screen effects for that cinematic polish or gameplay feedback. We've really journeyed through the whole pipeline of Unity's visual effects.
Indeed, this deep dive should hopefully arm you with a much better understanding of how to make your Unity projects not just look good, but look stunning, run efficiently, and feel deeply immersive. You've got a solid foundation now to analyze, maybe debug, and certainly create more sophisticated visual experiences. You know the tricks behind the curtain.
Now, So what does this all mean for you the listener? Given this incredible power of shaders not just to paint pixels, but to store data, change shapes, simulate physics, alter perception, what unthought of visual experience could you create by combining just two of these techniques that maybe aren't normally paired together.
Yeah, Like, what if procedural textures didn't just create patterns, but actively drove the parameters of a complex cloth shader in real time?
Or what if Vertex animation wasn't just cosmetic but somehow reacted dynamically to screen space, blend modes being applied. What unexpected, artistic or gameplay frontiers could you explore by smashing these powerful tools together in new ways
