text:
John Sherwood hails from Bedford, Massachusetts - the snow belt of Boston's western suburbs. He first experienced the joys of skiing on the 240-foot vertical slopes of Nashoba Valley in Littleton, Massachusetts. As a teenager, he enjoyed skiing at Gunstock, Waterville Valley, and Stowe. A season pass holder at Timberline for the past 8 years, John now considers himself a connoisseur of West Virginia powder. John also enjoys skiing in Europe, where he has skied or visited over twenty resorts, mainly in Austria. More recently, he has taken a keen interest in Utah's Wasatch mountains.
In addition to DCSki, John has published winter sports related articles in the The Slovak Spectator, Financial Times, Ski Racing Magazine, and the SkiEurope Report, and has written five books on military history. His most recent, War in the Shallows: Navy Coastal and Riverine Warfare in Vietnam, will be published by the Government Printing Office in 2013.
Going Further Afield: Powder Mountain, Utah
- March 21, 2016 - On a recent ski trip to Utah, DCSki Columnist John Sherwood spent seven days skiing at Snowbasin, and then decided to mix things up by heading to Powder Mountain. Powder Mountain quickly became one of John's favorite ski areas in Utah. He describes why in this report.
Firsthand Report: Austria's Lech and the Arlberg
- February 22, 2015 - DCSki Columnist John Sherwood recently returned from a trip to the Alrberg ski region of Austria. "One could spend a month here and not ski every trail," John writes, "a season and not experience all of its ski routes and sidebound zones, and a lifetime, and never ski every off-piste line." John provides this detailed Firsthand Report on the expansive ski area located in the Alps.
Snowbasin: Why I Keep Returning
- May 24, 2014 - DCSki Columnist John Sherwood is drawn to Utah's Snowbasin Resort, and he likes the ski area so much, he keeps returning. John describes the charisma and presence of Snowbasin in this story.
Shots of the Day: Austrian Visit
- October 7, 2012 - DCSki Columnist John Sherwood recently stopped by Zell am See Kaprun during a visit to Austria. Kaprun offers high elevation skiing up to 9,843 feet. John provides a few photos from his trip.
Book Review: Ski Training - How to Ski All Day, Volume 2, The Truth About Skiing
- April 24, 2012 - DCSki Columnist John Sherwood reviews a book that describes how to properly condition in preparation for the ski season.
Going Further Afield: Snowbasin
- March 23, 2012 - DCSki Columnist John Sherwood decided to forgo a ski trip to Europe, saving money by heading west to Utah's Snowbasin Resort instead. He has no regrets. John provides this detailed Firsthand Report from his trip to Snowbasin March 12-16, 2012.
Getting Fit for the Slopes: The Benefit of Strength Training for the Skier
- February 13, 2010 - We often perceive skiing more as a pastime than a sport, especially in this region where the slopes are short and almost always groomed to perfection. Skiing, though, involves many muscle groups, some of which never get properly exercised under normal circumstances. DCSki Columnist John Sherwood describes the benefits of strength training for on- and off-slope activities, using his own experiences as a guide.
Springtime Snapshots: The Canaan Valley Region in Late Spring
- June 25, 2008 - DCSki Columnist John Sherwood recently made a trip to the Canaan Valley region of West Virginia, where he visited Dolly Sods, Roaring Plains (South Prong Trail), and the Canaan Valley National Wildlife Refuge. He provides some photos from his visit.
The Transplanted: A DC Skier Heads West
- December 1, 2007 - Many DCSki readers know Tim Romano and his wife Madeline. They're regular attendees at DCSki slope-side gatherings. After spending 28 years in the DC area, Tim recently packed up and moved to Logan, Utah. DCSki Columnist John Sherwood interviews Tim to learn about the differences in skiing and lifestyle between the Mid-Atlantic region and a state that includes the word "Ski" on its license plate.
Spot Report: Timberline Four Seasons Resort, January 21, 2007
- January 23, 2007 - John Sherwood skied at West Virginia's Timberline Resort on Sunday, and provides this Firsthand Report.


text:
Image view and sampler
In this chapter we're going to create two more resources that are needed for the graphics pipeline to sample an image. The first resource is one that we've already seen before while working with the swap chain images, but the second one is new - it relates to how the shader will read texels from the image.
Texture image view
We've seen before, with the swap chain images and the framebuffer, that images are accessed through image views rather than directly. We will also need to create such an image view for the texture image.
Add a class member to hold a
VkImageView for the texture image and create a
new function
createTextureImageView where we'll create it:
VDeleter<VkImageView> textureImageView{device, vkDestroyImageView};
void initVulkan() {
void createTextureImageView() {
The code for this function can be based directly on
createImageViews. The only
two changes you have to make are the
format and the
VkImageViewCreateInfo viewInfo = {};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = textureImage;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
I've left out the explicit
viewInfo.components initialization, because
VK_COMPONENT_SWIZZLE_IDENTITY is defined as
0 anyway. Finish creating the
image view by calling
if (vkCreateImageView(device, &viewInfo, nullptr, textureImageView.replace()) != VK_SUCCESS) {
throw std::runtime_error("failed to create texture image view!");
Because so much of the logic is duplicated from
createImageViews, you may wish
to abstract it into a new
createImageView function:
void createImageView(VkImage image, VkFormat format, VDeleter<VkImageView>& imageView) {
VkImageViewCreateInfo viewInfo = {};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
if (vkCreateImageView(device, &viewInfo, nullptr, imageView.replace()) != VK_SUCCESS) {
throw std::runtime_error("failed to create texture image view!");
createTextureImageView function can now be simplified to:
void createTextureImageView() {
createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, textureImageView);
createImageViews can be simplified to:
void createImageViews() {
swapChainImageViews.resize(swapChainImages.size(), VDeleter<VkImageView>{device, vkDestroyImageView});
for (uint32_t i = 0; i < swapChainImages.size(); i++) {
createImageView(swapChainImages[i], swapChainImageFormat, swapChainImageViews[i]);
It is possible for shaders to read texels directly from images, but that is not very common when they are used as textures. Textures are usually accessed through samplers, which will apply filtering and transformations to compute the final color that is retrieved.
These filters are helpful to deal with problems like oversampling. Consider a texture that is mapped to geometry with more fragments than texels. If you simply took the closest texel for the texture coordinate in each fragment, then you would get a result like the first image:
If you combined the 4 closest texels through linear interpolation, then you would get a smoother result like the one on the right. Of course your application may have art style requirements that fit the left style more (think Minecraft), but the right is preferred in conventional graphics applications. A sampler object automatically applies this filtering for you when reading a color from the texture.
Undersampling is the opposite problem, where you have more texels than fragments. This will lead to artifacts when sampling high frequency patterns like a checkerboard texture at a sharp angle:
As shown in the left image, the texture turns into a blurry mess in the distance. The solution to this is anisotropic filtering, which can also be applied automatically by a sampler.
Aside from these filters, a sampler can also take care of transformations. It determines what happens when you try to read texels outside the image through its addressing mode. The image below displays some of the possibilities:
We will now create a function
createTextureSampler to set up such a sampler
object. We'll be using that sampler to read colors from the texture in the
shader later on.
void initVulkan() {
void createTextureSampler() {
Samplers are configured through a
VkSamplerCreateInfo structure, which
specifies all filters and transformations that it should apply.
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
magFilter and
minFilter fields specify how to interpolate texels that
are magnified or minified. Magnification concerns the oversampling problem
describes above, and minification concerns undersampling. The choices are
VK_FILTER_NEAREST and
VK_FILTER_LINEAR, corresponding to the modes
demonstrated in the images above.
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
The addressing mode can be specified per axis using the
addressMode fields.
The available values are listed below. Most of these are demonstrated in the
image above. Note that the axes are called U, V and W instead of X, Y and Z.
This is a convention for texture space coordinates.
VK_SAMPLER_ADDRESS_MODE_REPEAT: Repeat the texture when going beyond the image dimensions.
VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: Like repeat, but inverts the coordinates to mirror the image when going beyond the dimensions.
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: Take the color of the edge closest to the coordinate beyond the image dimensions.
VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: Like clamp to edge, but instead uses the edge opposite to the closest edge.
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: Return a solid color when sampling beyond the dimensions of the image.
It doesn't really matter which addressing mode we use here, because we're not going to sample outside of the image in this tutorial. However, the repeat mode is probably the most common mode, because it can be used to tile textures like floors and walls.
samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = 16;
These two fields specify if anisotropic filtering should be used. There is no
reason not to use this unless performance is a concern. The
field limits the amount of texel samples that can be used to calculate the final
color. A lower value results in better performance, but lower quality results.
There is no graphics hardware available today that will use more than 16
samples, because the difference is negligible beyond that point.
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK ;
borderColor field specifies which color is returned when sampling beyond
the image with clamp to border addressing mode. It is possible to return black,
white or transparent in either float or int formats. You cannot specify an
arbitrary color.
samplerInfo.unnormalizedCoordinates = VK_FALSE;
unnormalizedCoordinates field specifies which coordinate system you want
to use to address texels in an image. If this field is
VK_TRUE, then you can
simply use coordinates within the
[0, texWidth) and
[0, texHeight) range. If
it is
VK_FALSE, then the texels are addressed using the
[0, 1) range on all
axes. Real-world applications almost always use normalized coordinates, because
then it's possible to use textures of varying resolutions with the exact same
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
If a comparison function is enabled, then texels will first be compared to a value, and the result of that comparison is used in filtering operations. This is mainly used for percentage-closer filtering on shadow maps. We'll look at this in a future chapter.
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f;
All of these fields apply to mipmapping. We will look at mipmapping in a future chapter, but basically it's another type of filter that can be applied.
The functioning of the sampler is now fully defined. Add a class member to
hold the handle of the sampler object and create the sampler with
VDeleter<VkImageView> textureImageView{device, vkDestroyImageView};
VDeleter<VkSampler> textureSampler{device, vkDestroySampler};
void createTextureSampler() {
if (vkCreateSampler(device, &samplerInfo, nullptr, textureSampler.replace()) != VK_SUCCESS) {
throw std::runtime_error("failed to create texture sampler!");
Note the sampler does not reference a
VkImage anywhere. The sampler is a
distinct object that provides an interface to extract colors from a texture. It
can be applied to any image you want, whether it is 1D, 2D or 3D. This is
different from many older APIs, which combined texture images and filtering into
a single state.
In the next chapter we will expose the image and sampler objects to the shaders to draw the texture onto the square.

subset: commoncrawl