當前位置:
首頁 > 知識 > Vulkan Tutorial 26 view and sampler

Vulkan Tutorial 26 view and sampler

操作系統:Windows8.1

顯卡:Nivida GTX965M

開發工具:Visual Studio 2017

在本章節我們將為圖形管線創建另外兩個資源來對圖像進行採樣。第一個資源我們之前已經接觸過了,就是交換鏈,但是第二個資源比較新,它涉及著色器如何從圖像中讀取紋素。

Texture image view

我們之前看過交換鏈和幀緩衝區,通過圖像視圖而不是位元組訪問圖像。我們也會藉助圖像視圖來訪問貼圖圖像。

添加一個類成員變數vkImageView保存貼圖圖像,並且創建新的函數createTextureImageView

VkImageView textureImageView;

...

void initVulkan {
...
createTextureImage;
createTextureImageView;
createVertexBuffer;
...
}

...

void createTextureImageView {

}

函數中的代碼可以主要基於createImageViews。僅有的兩個變化是formatimage欄位:

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;

這裡已經省略了顯示的viewInfo.components初始化,因為VK_COMPONET_SWIZZLE_IDENTITY被定義為0。最後在函數中通過調用vkCreateImageView完成圖像視圖的創建:

if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) {
throw std::runtime_error("failed to create texture image view!");
}

因為很多邏輯都是從createImageViews複製過來的,所以可以抽象一個新的函數createImageView封裝該部分邏輯。

VkImageView createImageView(VkImage image, VkFormat format) {
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;

VkImageView imageView;
if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) {
throw std::runtime_error("failed to create texture image view!");
}

return imageView;
}

createTextureImageView函數可以簡化為:

void createTextureImageView {
textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM);
}

createImageViews可以簡化為:

void createImageViews {
swapChainImageViews.resize(swapChainImages.size);

for (uint32_t i = 0; i < swapChainImages.size; i++) { swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat); } }

確保程序退出的時候銷毀圖像視圖,並在銷毀圖像本身前清理圖像視圖。

Samplers

著色器直接從圖像中讀取紋素是可以的,但是當它們作為貼圖紋理的時候並不常見。貼圖紋理通常使用採樣器來訪問,這以為著使用過濾器和變換來計算最終的顏色。

這些過濾器有助於處理超載採樣的問題。考慮一個映射到幾何圖形的紋理貼圖,擁有比紋素更多的片元。如果只是在每個片段中使用最接近的紋理坐標,那麼會獲得第一個圖像的結果:

Vulkan Tutorial 26 view and sampler

如果混合最近的四個紋素通過顯性插值,我們會看到更加平滑的結果,如右圖所示。當然,應用程序可能具有符合左側風格的藝術要求(比如Minecraft),但是常規的圖形應用程序中更傾向右側的效果。當從紋理中讀取一個顏色的時候,採樣器自動應用過濾器。

如果採樣負載採樣也會造成問題。當採樣頻率過高的時候,比如對於棋盤的紋理進行採樣,會導致在有銳度角的地方產生幻影。

Vulkan Tutorial 26 view and sampler

如作左側圖示,順著距離的變化,紋理變的模糊且混亂的。解決方案是各向異性過濾 anisotropic filtering,它會自動被採樣器應用。

除了這些過濾器,採樣器也關注變換。當嘗試讀取圖像外的紋素的時候,採用什麼定址模式。下圖顯示了一些可能的模式:

Vulkan Tutorial 26 view and sampler

添加新函數createTextureSampler配置採樣器對象。我們稍後會使用它從著色器中讀取顏色。

void initVulkan {
...
createTextureImage;
createTextureImageView;
createTextureSampler;
...
}

...

void createTextureSampler {

}

採樣器通過VkSamplerCreateInfo結構體配置,它用來指定將要應用的過濾器和變換。

VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;

magFilter和minFilter過濾器欄位指定紋素放大和縮小內插值方式。放大關註上文描述的超採樣問題,縮小關注負載採樣的問題。VK_FILTER_NEARESTVK_FILTER_LINEAR是可選的選項,對應上面圖片紕漏的模式。

samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;

可以使用addressMode欄位指定每個軸向使用的定址模式。有效的值列在下方。大多數在圖像中已經解釋說明過了。需要注意的是軸向在這裡稱為 U,V 和 W 代替 X,Y 和 Z。這是紋理空間坐標的約定。

  • VK_SAMPLER_ADDRESS_MODE_REPEAT

    :當超過圖像尺寸的時候採用循環填充。
  • VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT

    :與循環模式類似,但是當超過圖像尺寸的時候,它採用反向鏡像效果。
  • VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE

    :當超過圖像尺寸的時候,採用邊緣最近的顏色進行填充。
  • VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TOEDGE

    :與邊緣模式類似,但是使用與最近邊緣相反的邊緣進行填充。
  • VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER

    :當採樣超過圖像的尺寸時,返回一個純色填充。

在這裡使用什麼樣的定址模式並不重要,因為我們不會在圖像之外進行採樣。但是循環模式是普遍使用的一種模式,因為它可以用來實現諸如瓦片地面和牆面的紋理效果。

samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = 16;

這兩個欄位指定是否使用各向異性過濾器。沒有理由不使用該特性,除非性能是一個問題。maxAnisotropy欄位限制可用於計算最終顏色的紋素採樣的數量。低的數值會得到比較好的性能,但是回得到較差的質量。當前沒有任何的圖形硬體可以使用查過16個採樣器,因為與其超過16個採樣器之間的差異可以忽略不計。

samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;

borderColor欄位指定採樣範圍超過圖像時候返回的顏色,與之對應的是邊緣定址模式。可以以float或者int格式返回黑色,白色或者透明度。但是不能指定任意顏色。

samplerInfo.unnormalizedCoordinates = VK_FALSE;

unnormalizedCoordinates欄位指定使用的坐標系統,用於訪問圖像的紋素。如果欄位為VK_TRUE,意味著可以簡單的使用坐標範圍為[ 0, texWidth )[ 0, texHeight )。如果使用VK_FALSE,意味著每個軸向紋素訪問使用[ 0, 1)範圍。真實的應用程序總是使用歸一化的坐標。因為這樣可以使用完全相同坐標的不同解析度的紋理。

samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;

如果開啟比較功能,那麼紋素首先和值進行比較,並且比較後的值用於過濾操作。主要用在陰影紋理映射的 percentage-closer filtering即百分比近似過濾器。我們會在未來的章節中看到。

samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f;

所有這些欄位應用在mipmapping。mipmapping也在未來章節中看到,但是基本的它可以應用另一種濾波器。

採樣器的功能現在已經完整的定義了。添加類成員持有採樣器對象的引用並通過vkCreateSampler創建採樣器:

VkImageView textureImageView;
VkSampler textureSampler;

...

void createTextureSampler {
...

if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) {
throw std::runtime_error("failed to create texture sampler!");
}
}

需要注意的是採樣器沒有任何地方引用VkImage。採樣器是一個獨特的對象,它提供了從紋理中提取顏色的介面。它可以應用在任何你期望的圖像中,無論是1D,2D,或者是3D。也與之前很多舊的API是不同的,後者將紋理圖像與過濾器混合成單一狀態。

在程序的最後且不再訪問圖像的時候,銷毀採樣器:

void cleanup {
cleanupSwapChain;

vkDestroySampler(device, textureSampler, nullptr);
vkDestroyImageView(device, textureImageView, nullptr);

...
}

Anisotropy device feature

如果現在運行程序,你會看到validation layer消息如下:

這是因為各向異性濾波器是一個可選的特性。我們需要更新createLogicalDevice函數請求它:

VkPhysicalDeviceFeatures deviceFeatures = {};
deviceFeatures.samplerAnisotropy = VK_TRUE;

並且儘管現在的圖形卡不太可能不支持該功能,但建議仍然更新isDeviceSuitable函數去檢測是否有效:

bool isDeviceSuitable(VkPhysicalDevice device) {
...

VkPhysicalDeviceFeatures supportedFeatures;
vkGetPhysicalDeviceFeatures(device, &supportedFeatures);

return indices.isComplete && extensionsSupported && supportedFeatures.samplerAnisotropy;
}

vkGetPhysicalDeviceFeaturesVkPhysicalDeviceFeatures結構重新定義,指定哪些特性被支持而不是通過設置boolean值來請求。

如果不是強制使用各向異性濾波器,也可以簡單的通過條件設定來不使用它:

samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = 1;

下一章我們將圖像與採樣器對象公開到著色器中,繪製紋理到正方形上。

項目代碼 GitHub地址。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

Django 學習筆記(二)第一個網頁
vue.js+UEditor集成
JS基本類型和引用類型
Centos操作系統在虛擬機VMware上的安裝
PostgreSQL 使用 PreparedStatement 導致查詢慢的分析

TAG:科技優家 |

您可能感興趣

Rogue Swarm demo:將Vulkan和PowerVR Series8XE帶入我們的生活
Oculus Quest和Go現已支持Vulkan
Oculus Medium 2.0更新採用Vulkan新渲染引擎提高解析度
Intel OpenCV庫支持Vulkan:獨立顯卡走來
Vulkan即將推出macOS和iOS,但不會感謝Apple
[視頻]歌計劃在 Android P 中支持圖形 API Vulkan 1.1
Flyme 7體驗版王者榮耀Vulkan來了 不過Pro 7除外
新面孔Model】陳曦出鏡美國版《Vulkan Magazine》一月刊時尚大片
研發實戰:如何在Oculus Mobile VR平台進行Vulkan開發
AMD終止支持功勛API Mantle:曾催生DX12、Vulkan
Wine 3.3開發版發布:Bug修復 支持Vulkan!
Android Q將原生支持Vulkan,安卓手機和手游的春天?
Vulkan API終於登陸macOS/iOS平台 但與蘋果無關
Vulkan API 終於登陸 macOS、iOS,但與蘋果無關
Android Q將支持Vulkan原生渲染引擎:流暢度/遊戲體驗大提升
《殭屍世界大戰》開啟Vulkan AMD Vega 64表現如何?
Flyme 7體驗版11.13發布:支持王者榮耀Vulkan模式
《殭屍世界大戰》開啟Vulkan:AMD Vega 64性能超了RTX 2080 Ti
Wine 3.3上線:首次支持Vulkan圖形介面 修復35處BUG
Vulkan下RTX2080Ti竟沒法玩《殭屍世界大戰》?