Shader Programming, Volume 3

Textures, UVs, and Normals

Sebastian Monroy
4 min readJun 18, 2016

In the last post we learned how to make a diffuse untextured shader. This has been pretty dry so far but I think we’re about to get to some good stuff so hang in there. Can’t overlook the basics.

Chapter 2.3

Surface Shaders and Texture Mapping, Adding a texture to a shader

We start by making a new shader based on Unity’s Standard Shader and calling it TexturedShader. Create a corresponding material TexturedMaterial and import a cool texture to play with while you’re at it.

Some important things to note about how the Standard Shader incorporates a texture are in the comments in the following code:

Inside the surf() function, the UV data is used to sample the texture using the tex2D() function of Cg. It takes a texture and UV and returns the color of the pixels at that position.

Note that the U and V coordinates go from 0 to 1, where (0,0) and (1,1) correspond to two opposite corners.

There are also a bunch of import settings you can alter for the texture. The Filter Mode, for example, determines how colors are interpolated when the texture is sampled. For most applications, Bilinear provides an inexpensive yet effective way to smooth the texture. If this produces blurred lines you can use Point to remove any interpolation from the texture mapping.

The Aniso Level property is useful for reducing unpleasant artifacts when you view a texture from a steep angle, as with floor textures and ceiling textures.

When we use our new shader to apply a woodgrain texture to the foremost sphere in our test scene it looks like this.

Nice!

Next we’ll learn how to create a shader that animates a texture on the surface of an object.

Chapter 2, part 4

Surface Shaders and Texture Mapping, Scrolling textures by modifying UV values

We’re gonna need to make a new shader with a couple more properties for this one.

As we’ve learned, to be able to access the values from these properties we need to create new variables in the CGPROGRAM section.

As always, the fun stuff happens in surf(). That’s where we’ll manipulate the UVs of the inputted texture using the built-in _Time variable. The _Time variable gives us an incremented float value based on Unity’s game time clock, which is useful for animating shaders.

If you’re curious like I was, you can find Unity’s other built-in shader variables here.

Altogether, the final code for the ScrollingShader is as follows:

And with our new material applied to our wood-textured sphere we get this neat result!

It’s important to note that we’re not actually animating the texture — we’re faking it by manipulating the current UVs of the inputted texture and passing them back to the texture as its new UVs every frame.

Chapter 2.5

Surface Shaders and Texture Mapping, Normal mapping

As you’re probably aware, 3D models are generally composed of triangles and each of these triangles faces a different direction. The triangles reflect light according to this facing direction. This can be a problem when representing curved objects if the way a mesh reflects light is dependent only on the facing directions of its triangles.

via http://goo.gl/jnIFw7

It can be painfully obvious that the its curved geometry is composed of flat triangles. And sometimes we don’t want that.

To avoid this problem, the way that light reflects off of a triangle is determined by its normal direction instead.

Regardless of the facing direction, every point within a triangle has its own normal direction that is a linear interpolation of the ones stored in its vertices, producing the effect of high-resolution geometry on a low resolution model.

Instead of calculating normals from the 3D model, the normal directions can be provided using an additional texture called a normal map or a bump map. Normal maps are RGB images where the R, G, and B components are used to store the X, Y, and Z components of the normal direction on every point of a model.

Let’s make a simple normal mapping shader, starting with the properties block. We’ll only need properties for the color tint and normal texture. I added a normal intensity property too, so that the effect the normal map has can be altered.

We know the basic structure of a shader program now so I’ll just skip to the final code.

Now that’s a cushy sphere!

Check out how the light interacts with the creases formed by the buttons.

Those creases are not part of the sphere’s geometry, but normal maps are a convincing and efficient method of giving the surface apparent depth.

I think I’ll take a break now.

Up next is transparent materials!

--

--