let's 👏 talk 👏 about 👏 normals

I see a lot of confusion on this topic among Unity devs and other people dealing with fragment shaders, so let's talk about normals!

A "normal" is the direction something is facing. We use normals in shaders for diffuse lighting, specular reflections, rim highlights, and so on. But things can get tricky because all directions are relative, and different effects require different reference points, or "spaces"

  • Directions relative to the screen are in view space.
  • Directions relative to the scene are in world space.
  • Directions relative to the mesh are in object space.
  • Directions relative to an individual fragment are in tangent space.

Let's see how these work in practice.

We can visualize a normal by turning it into a color, X becomes red, Y becomes green, Z becomes blue. This is the idea behind normal maps. However, when we work with normals in a shader, they are generally vectors with a magnitude of 1, that is, the values can be between -1 and 1 (an absolute value of 1). Since there is no such thing as a negative color, for the whole range to be visible, to view a normal as a color we squish its value to go between 0 and 1, so that 0.5 in the color is actually 0 in the vector. This is done by multiplying the value by 0.5 then adding 0.5. So if you use a color picker to grab a color from the following images, to convert the value back to the vector that color actually represents, you would multiply it by two, then subtract one. With that in mind, we can have a look at the different kinds of normals.

Object Normals

Here we are seeing object normals. Notice how when I change my POV to look behind the character, the back of the mesh is yellow, and when my POV is fixed while I rotate the character, the back of the mesh is still yellow.

You access object normals in the fragment function simply by passing them along from the vertex function as-is from the appdata (the asset's own data). Object normals are useful when you need to do something to a specific part of the mesh regardless of its rotation.

Tangent Normals

Here we have tangent normals. these are relative to the part of the mesh being shaded each time the fragment function is run. basically, if the mesh was a planet, tangent normals would be relative to the POV of a person standing on it.

We generally get tangent normals from normal maps, 2D textures that use RGB to store XYZ. The fact that they work the same way no matter what part of the mesh they're on is the point, if they were relative to any other anchor they wouldn't work except at predetermined angles. Most of the time tangent normals are added to world normals to get more detailed lighting, but tangent normals are often used on their own for parallax offsets or parallax occlusion mapping.

World Normals

Here we see world normals. Notice that when I look at the mesh from different places in the scene, we see different colors, but when the mesh is rotated in place, the colors we see are the same. world normals are relative to the scene's origin (the "world" of the game.)

World normals are particularly handy when comparing the object being shaded to other things in the scene, such as lights (this is how we figure out what parts should be bright vs in shadow) or view direction  (for speculars, rims, etc.) or a fixed direction (triplanar mapping.)

View Normals

These are view normals. notice how the color of the object stays the same regardless of the placement of my POV or the rotation of the object. The values are locked to the screen.

View normals are are handy for extruded hull outlines, shader-based billboarding, faux depth effects when depth texture is unavailable, etc. If you're used to raymarching in GLSL, these are the kinds of normals you work with in that situation. This effect of mine uses world normals for the fresnel & view normals for the color split.

World View Direction

Not a type of normal, per se, but often used with normals for lighting, is world view direction. Notice how the color is more uniform over the mesh, because the angle of the object's vertices don't matter here, just the angle from your view to the object.

Try it out!

I've attached the shader I wrote for this little demonstration to this post as NormalViewer.shader . The "Mode" slider cycles through the different kinds of normals we looked at (and world view direction.) Take it for a spin and see what your favorite meshes look like!

Get more from Team Dogpit

72
Unlock 72 exclusive posts
Be part of the community
Connect via private message

Team Dogpit

creating Unity shader tutorials and cool graphics!

Team Dogpit

creating Unity shader tutorials and cool graphics!

Tiers
Comrade
$2 per month
Reward
  • get a cool Dogpit Discord role
  • Early access to gameplay demos
  • see my commit messages and other patron-only posts
  • Early access to tutorials and shared code
  • Help make it possible for me to keep making tutorials that everyone can enjoy!
Includes Discord benefits
Vanguard
$5 per month
Reward
  • More WIP screenshots and full res images
  • Access to exclusive editor utilities, advanced shaders, and other neat things I cook up
  • Everything from previous tier
Includes Discord benefits
Ghost Process
$50 per month
Reward
  • Exclusive screenshots of the Valentin model in sexy poses
  • Everything from previous tiers
Includes Discord benefits
Recent Posts