版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.10.08 星期一 |
前言
很多做視頻和圖像的乐设,相信對這個框架都不是很陌生,它渲染高級3D圖形姻采,并使用GPU執(zhí)行數(shù)據(jù)并行計算。接下來的幾篇我們就詳細的解析這個框架爵憎。感興趣的看下面幾篇文章慨亲。
1. Metal框架詳細解析(一)—— 基本概覽
2. Metal框架詳細解析(二) —— 器件和命令(一)
3. Metal框架詳細解析(三) —— 渲染簡單的2D三角形(一)
4. Metal框架詳細解析(四) —— 關(guān)于GPU Family 4(一)
5. Metal框架詳細解析(五) —— 關(guān)于GPU Family 4之關(guān)于Imageblocks(二)
6. Metal框架詳細解析(六) —— 關(guān)于GPU Family 4之關(guān)于Tile Shading(三)
7. Metal框架詳細解析(七) —— 關(guān)于GPU Family 4之關(guān)于光柵順序組(四)
8. Metal框架詳細解析(八) —— 關(guān)于GPU Family 4之關(guān)于增強的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細解析(九) —— 關(guān)于GPU Family 4之關(guān)于線程組共享(六)
10. Metal框架詳細解析(十) —— 基本組件(一)
11. Metal框架詳細解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細解析(十二) —— 基本組件之器件選擇 - 計算處理的設(shè)備選擇(三)
13. Metal框架詳細解析(十三) —— 計算處理(一)
14. Metal框架詳細解析(十四) —— 計算處理之你好,計算(二)
15. Metal框架詳細解析(十五) —— 計算處理之關(guān)于線程和線程組(三)
16. Metal框架詳細解析(十六) —— 計算處理之計算線程組和網(wǎng)格大斜摹(四)
17. Metal框架詳細解析(十七) —— 工具刑棵、分析和調(diào)試(一)
18. Metal框架詳細解析(十八) —— 工具、分析和調(diào)試之Metal GPU Capture(二)
19. Metal框架詳細解析(十九) —— 工具愚铡、分析和調(diào)試之GPU活動監(jiān)視器(三)
20. Metal框架詳細解析(二十) —— 工具蛉签、分析和調(diào)試之關(guān)于Metal著色語言文件名擴展名、使用Metal的命令行工具構(gòu)建庫和標記Metal對象和命令(四)
21. Metal框架詳細解析(二十一) —— 基本課程之基本緩沖區(qū)(一)
Basic Texturing - 基本紋理
演示如何加載圖像數(shù)據(jù)和紋理四邊形茂附。
在Basic Buffers示例中正蛙,您學習了如何在Metal中渲染基本幾何體。
在此示例中营曼,您將學習如何通過將紋理應(yīng)用于單個四邊形來渲染2D圖像乒验。 特別是,您將學習如何配置紋理屬性蒂阱,解釋紋理坐標以及訪問片段函數(shù)中的紋理锻全。
Images and Textures - 圖像和紋理
任何圖形技術(shù)的一個關(guān)鍵特性是處理和繪制圖像的能力。 Metal以包含圖像數(shù)據(jù)的紋理形式支持此功能录煤。 與常規(guī)2D圖像不同鳄厌,紋理可以以更具創(chuàng)造性的方式使用,并應(yīng)用于更多表面類型妈踊。 例如了嚎,紋理可用于替換選定的頂點位置,或者它們可以完全包裹在3D對象周圍廊营。 在此示例中歪泳,圖像數(shù)據(jù)被加載到紋理中,應(yīng)用于單個四邊形露筒,并呈現(xiàn)為2D圖像呐伞。
Load Image Data - 加載圖像數(shù)據(jù)
Metal
框架不提供直接將文件中的圖像數(shù)據(jù)加載到紋理的API。 相反慎式,Metal應(yīng)用程序或游戲依賴于自定義代碼或其他框架(如Image I / O伶氢,MetalKit趟径,UIKit
或AppKit
)來處理圖像文件。 Metal本身僅分配紋理資源癣防,然后使用先前加載到內(nèi)存中的圖像數(shù)據(jù)填充它們蜗巧。
在此示例中,為簡單起見劣砍,自定義AAPLImage
類將圖像數(shù)據(jù)從文件(Image.tga)
加載到內(nèi)存(NSData)
中惧蛹。
注意:
AAPLImage
類不是此示例的焦點,因此不對其進行詳細討論刑枝。 該類演示了基本的圖像加載操作,但不以任何方式使用或依賴于Metal框架迅腔。 其唯一目的是便于加載該特定示例的圖像數(shù)據(jù)装畅。
此示例使用TGA
文件格式以簡化。 該文件由描述元數(shù)據(jù)的標題(例如圖像尺寸)和圖像數(shù)據(jù)本身組成沧烈。 這種文件格式的關(guān)鍵點是圖像數(shù)據(jù)的存儲器布局掠兄;特別是每個像素的布局。
Metal要求使用特定的MTLPixelFormat
值格式化所有紋理锌雀。 像素格式描述了每個紋理像素(其紋理像素)的布局蚂夕。 要使用圖像數(shù)據(jù)填充Metal紋理,其像素數(shù)據(jù)必須已經(jīng)采用Metal
兼容的像素格式進行格式化腋逆,該格式由單個MTLPixelFormat
枚舉值定義婿牍。 此示例使用MTLPixelFormatBGRA8Unorm
像素格式,表示每個像素具有以下內(nèi)存布局:
此像素格式使用每像素32位惩歉,按照藍色等脂,綠色,紅色和alpha順序排列為每個組件8位撑蚌。 每個像素使用32位的TGA
文件已經(jīng)以這種格式排列上遥,因此不需要進一步的轉(zhuǎn)換操作。 但是争涌,此示例使用每像素24位BGR
圖像粉楚,需要為每個像素添加額外的8位alpha分量。 由于alpha通常定義圖像的不透明度亮垫,并且樣本的圖像完全不透明模软,因此32位BGRA像素的附加8位alpha分量設(shè)置為255。
在AAPLImage
類加載圖像文件之后包警,可以通過對data
屬性的查詢來訪問圖像數(shù)據(jù)撵摆。
// Initialize a source pointer with the source image data that's in BGR form
uint8_t *srcImageData = ((uint8_t*)fileData.bytes +
sizeof(TGAHeader) +
tgaInfo->IDSize);
// Initialize a destination pointer to which you'll store the converted BGRA
// image data
uint8_t *dstImageData = mutableData.mutableBytes;
// For every row of the image
for(NSUInteger y = 0; y < _height; y++)
{
// For every column of the current row
for(NSUInteger x = 0; x < _width; x++)
{
// Calculate the index for the first byte of the pixel you're
// converting in both the source and destination images
NSUInteger srcPixelIndex = 3 * (y * _width + x);
NSUInteger dstPixelIndex = 4 * (y * _width + x);
// Copy BGR channels from the source to the destination
// Set the alpha channel of the destination pixel to 255
dstImageData[dstPixelIndex + 0] = srcImageData[srcPixelIndex + 0];
dstImageData[dstPixelIndex + 1] = srcImageData[srcPixelIndex + 1];
dstImageData[dstPixelIndex + 2] = srcImageData[srcPixelIndex + 2];
dstImageData[dstPixelIndex + 3] = 255;
}
}
_data = mutableData;
Create a Texture - 創(chuàng)建紋理
MTLTextureDescriptor
對象用于配置MTLTexture
對象的紋理尺寸和像素格式等屬性。 然后調(diào)用newTextureWithDescriptor:
方法創(chuàng)建一個空紋理容器并為紋理數(shù)據(jù)分配足夠的內(nèi)存害晦。
MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];
// Indicate that each pixel has a blue, green, red, and alpha channel, where each channel is
// an 8-bit unsigned normalized value (i.e. 0 maps to 0.0 and 255 maps to 1.0)
textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm;
// Set the pixel dimensions of the texture
textureDescriptor.width = image.width;
textureDescriptor.height = image.height;
// Create the texture from the device by using the descriptor
_texture = [_device newTextureWithDescriptor:textureDescriptor];
與存儲多種自定義數(shù)據(jù)的MTLBuffer
對象不同暑中,MTLTexture
對象專門用于存儲格式化的圖像數(shù)據(jù)鲫剿。 盡管MTLTextureDescriptor
對象指定了足夠的信息來分配紋理內(nèi)存,但還需要其他信息來填充空紋理容器灵莲。 通過replaceRegion:mipmapLevel:withBytes:bytesPerRow:
方法用MTLTexture
對象填充圖像數(shù)據(jù)雕凹。
圖像數(shù)據(jù)通常按行組織政冻。 此示例計算每行的字節(jié)數(shù),即每個像素的字節(jié)數(shù)乘以圖像寬度明场。 這種類型的圖像數(shù)據(jù)被認為是緊密打包(tightly packed)
的汽摹,因為后續(xù)像素行的數(shù)據(jù)緊跟在前一行之后。
NSUInteger bytesPerRow = 4 * image.width;
紋理具有已知的尺寸苦锨,可以解釋為像素區(qū)域。 MTLRegion
結(jié)構(gòu)用于標識紋理的特定區(qū)域舟舒。 此示例使用圖像數(shù)據(jù)填充整個紋理;因此氏仗,覆蓋整個紋理的像素區(qū)域等于紋理的尺寸莺治。
MTLRegion region = {
{ 0, 0, 0 }, // MTLOrigin
{image.width, image.height, 1} // MTLSize
};
注意:要指定紋理的子區(qū)域,
MTLRegion
結(jié)構(gòu)必須具有非零原點值或任何紋理尺寸的較小尺寸值床佳。
每行和特定像素區(qū)域的字節(jié)數(shù)是用于使用圖像數(shù)據(jù)填充空紋理容器的必需參數(shù)榄审。 調(diào)用replaceRegion:mipmapLevel:withBytes:bytesPerRow:
方法通過將image.data.bytes
指針中的數(shù)據(jù)復(fù)制到_texture
對象來執(zhí)行此操作。
[_texture replaceRegion:region
mipmapLevel:0
withBytes:image.data.bytes
bytesPerRow:bytesPerRow];
Texture Coordinates - 紋理坐標
片段函數(shù)的主要任務(wù)是處理傳入的片段數(shù)據(jù)并計算可繪制像素的顏色值浪感。此示例的目標是通過將紋理應(yīng)用于單個四邊形來顯示屏幕上每個紋素的顏色饼问。因此,樣本的片段函數(shù)必須能夠讀取每個紋素并輸出其顏色峻堰。
紋理不能單獨渲染;它必須對應(yīng)于頂點函數(shù)輸出的一些幾何表面旦万,并由光柵化器變成碎片镶蹋。此關(guān)系由紋理坐標定義:浮點位置成艘,將紋理圖像上的位置映射到幾何表面上的位置淆两。
對于2D紋理牧氮,紋理坐標在x和y方向上的值均為0.0到1.0。值(0.0,0.0)
映射到圖像數(shù)據(jù)的第一個字節(jié)(圖像的左下角)處的紋素。值(1.0,1.0)
映射到圖像數(shù)據(jù)的最后一個字節(jié)(圖像的右上角)處的紋素光坝。遵循這些規(guī)則,訪問圖像中心的紋素需要指定紋理坐標(0.5,0.5)
性含。
Map the Vertex Texture Coordinates - 映射頂點紋理坐標
要渲染完整的2D圖像商蕴,必須將包含圖像數(shù)據(jù)的紋理映射到定義2D四邊形的頂點上芝发。 在此示例中,每個四邊形的頂點指定一個紋理坐標格郁,將四邊形的角映射到紋理的角独悴。
static const AAPLVertex quadVertices[] =
{
// Pixel positions, Texture coordinates
{ { 250, -250 }, { 1.f, 0.f } },
{ { -250, -250 }, { 0.f, 0.f } },
{ { -250, 250 }, { 0.f, 1.f } },
{ { 250, -250 }, { 1.f, 0.f } },
{ { -250, 250 }, { 0.f, 1.f } },
{ { 250, 250 }, { 1.f, 1.f } },
};
vertexShader
頂點函數(shù)通過將這些值寫入RasterizerData
輸出結(jié)構(gòu)的textureCoordinate
成員中,沿管道傳遞這些值决采。 這些值在四邊形的三角形片段中進行插值坟奥,類似于Hello Triangle樣本中的插值顏色值拇厢。
out.textureCoordinate = vertexArray[vertexID].textureCoordinate;
Sample Texels - 示例特征
samplingShader
片段函數(shù)的簽名包括colorTexture
參數(shù)旺嬉,該參數(shù)具有texture2d
類型并使用[[texture(index)]]
屬性限定符厨埋。 此參數(shù)是對MTLTexture
對象的引用,用于讀取其紋素雨效。
fragment float4
samplingShader(RasterizerData in [[stage_in]],
texture2d<half> colorTexture [[ texture(AAPLTextureIndexBaseColor) ]])
讀取紋素也稱為采樣废赞。 片段函數(shù)使用內(nèi)置紋理sample()
函數(shù)來對texel
數(shù)據(jù)進行采樣。 sample()
函數(shù)有兩個參數(shù):一個采樣器(textureSampler)
和一個紋理坐標(in.textureCoordinate)
据悔。 采樣器用于計算紋理元素的顏色耘沼,紋理坐標用于定位特定紋理元素。
當渲染的區(qū)域與紋理的大小不同時菠隆,采樣器可以使用不同的算法來精確計算sample()
函數(shù)應(yīng)返回的texel
顏色狂秘。 mag_filter
模式指定當區(qū)域大于紋理大小時,采樣器應(yīng)如何計算返回的顏色破衔;min_filter
模式指定當區(qū)域小于紋理大小時碧查,采樣器應(yīng)如何計算返回的顏色。 為兩個濾鏡設(shè)置線性linear
模式可使采樣器平均給定紋理坐標周圍的紋素顏色传惠,從而使輸出圖像更平滑稻扬。
constexpr sampler textureSampler (mag_filter::linear,
min_filter::linear);
// Sample the texture to obtain a color
const half4 colorSample = colorTexture.sample(textureSampler, in.textureCoordinate);
Set a Fragment Texture - 設(shè)置片段紋理
此示例使用AAPLTextureIndexBaseColor
索引來標識Objective-C
和Metal Shading Language
代碼中的紋理泰佳。 片段函數(shù)也采用與頂點函數(shù)類似的參數(shù)尘吗,你可以調(diào)用setFragmentTexture:atIndex:
方法在特定索引處設(shè)置紋理浇坐。
[renderEncoder setFragmentTexture:_texture
atIndex:AAPLTextureIndexBaseColor];
在此示例中,您學習了如何通過將紋理應(yīng)用于單個四邊形來渲染2D圖像擒贸。
后記
本篇主要講述了基本紋理觉渴,感興趣的給個贊或者關(guān)注~~~