This state controls how the textures that are rendered by
the system are handled. Why is it called a sampler state rather than a
texture state? These settings are used when the texture is actually
sampled to get a particular color, rather than the state of the texture
itself.
The majority of
pre-created static members of the object have to do with texture
addressing. Normally, texture coordinates go from the range of 0 to 1,
but what if yours go beyond that? The texture addressing mode determines
how the texture is sampled from outside this range, so let’s take a
look at a quick example. Begin by creating a new Game project and adding
a texture to the Content project (for example, cat.jpg). Declare a
variable to hold your texture and one of your states as well:
Texture2D texture;
SamplerState linearMirror;
Initialize the following variables in your LoadContent method as normal:
texture = Content.Load<Texture2D>("cat");
linearMirror = new SamplerState();
linearMirror.AddressU = TextureAddressMode.Mirror;
linearMirror.AddressV = TextureAddressMode.Mirror;
linearMirror.AddressW = TextureAddressMode.Mirror;
linearMirror.Filter = TextureFilter.Linear;
Before we go on, let’s take a
look at the state you just created. As you can tell, you can set the
address mode on any of the components of the texture coordinates
separately (U,V, or W), although, in most cases, you simply set them all
to the same thing as you did here. We discuss what each of the three
valid address modes are in a moment after you see the other two. Replace
the Draw overload with the following and run the application:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
int seconds = (int)gameTime.TotalGameTime.TotalSeconds % 3;
SamplerState state = (seconds == 0) ? SamplerState.LinearClamp :
((seconds == 1) ? SamplerState.LinearWrap : linearMirror);
spriteBatch.Begin(SpriteSortMode.Deferred, null, state, null, null);
spriteBatch.Draw(texture, GraphicsDevice.Viewport.Bounds,
new Rectangle(-GraphicsDevice.Viewport.Width, -
GraphicsDevice.Viewport.Height,
GraphicsDevice.Viewport.Width * 3, GraphicsDevice.Viewport.Height * 3),
Color.White);
spriteBatch.End();
}
At
the beginning of this method, you first pick which sampler state you
will use, using a quick formula to change it every second between one of
three different states. The first is LinearClamp, which is just like the one you created previously, except Mirror replaced with Clamp as the addressing mode. Next is LinearWrap, which again, uses the Wrap
addressing mode. The final one is the mirror mode you created earlier.
What do each of these do? You can probably tell partially just by
running the example, which rotates through them as in Figure 1.
The first mode is Clamp.
This “clamps” your texture coordinates between 0 and 1. It does this by
artificially stretching the border pixels for the texture infinitely.
This is why when you see the cat rendering from the beginning, it looks
like it is smeared into position where you can bands to the left and
right, as well from the top and bottom of the texture.
Wrap,
which you see during the running example (and can somewhat tell from
the name), simply wraps the texture indefinitely in all directions. A UV
coordinate of 1.5,1.5 is read the same as a UV coordinate of 0.5,0.5.
The last mode is the Mirror mode, which is similar to Wrap
in that it repeats the image indefinitely, but each new image required
is flipped from the previous one. Notice that the flipping happens on
both the horizontal and vertical axis as well.
You might wonder how this
image was rendered with a set of texture coordinates outside of the 0,1
range. After all, you expect that using sprite batch renders only the
texture you passed in, and for the majority of cases, this is very true.
However, look at the third parameter to the sprite batch Draw
method here. You use a source rectangle that goes beyond the bounds of
the texture. The sprite batch detects this and maps the UV coordinates
across the range of the source rectangle, where the ranges from 0–1 are
the coordinates within the actual source of the texture, and everything
else is not.
The last parameter is the Filter
of the sampler, which dictates how the sample color is determined if it
isn’t exactly a single pixel (for example, it is between two pixels).
The XNA Game Studio runtime supports three different filters: Linear,
Point, and Anisotropic. Notice a few other permutations in the list of
possible values with various combinations of “min” (standing for minify,
the act of shrinking a texture), “mag” (standing for magnify, when a
texture is enlarged), and “mip” (standing for the mip levels, when you
have a texture with a set of mip maps). For example, the MinLinearMagPointMipLinear value means it uses linear filtering during minify, point filter during magnify, and linear filter during mipmapping.
What Is Mipmapping?
At a high level, mipmaps are a
collection of images representing a single texture at various depths.
Each image is half the size of the one before it. For example, if you
have a starting image that is 256×256 pixels, it has a series of eight
different additional images for different depths (or mip levels), of
sizes 128×128, 64×64, 32×32, 16×16, 8×8, 4×4, 2×2, and 1×1.
If your texture has
mipmaps, the runtime picks the appropriate sized image based on the
distance from the camera. Items extremely close to the camera use the
higher resolution images, and items far from the camera use the low
resolution images. Normally, mipmaps are generated by filtering the next
higher resolution down. However, there’s nothing stopping you from
having your artist give you the entire mipmap chain and using it
directly.
Although you can get a
boost in image quality by using mipmaps, one of the major disadvantages
is memory consumption. Because you store multiple different copies of
the image at different resolutions, you use at least double the memory.
Other Texture Types
Although you’ve been using mostly Texture2D and similar objects, there are actually two other types of textures available in the system as well. These are the TextureCube and Texture3D classes.
A cube texture (like the name implies) is a texture that includes six sides, such as in a cube. A common usage of this texture type for the
environment map effect is to render portions of the scene six times
(one for each face of the cube) into a cube render target and then use
it as your environment map.
Note
Texture3D are available only in the HiDef profile.