版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2018.10.08 星期一 |
前言
很多做視頻和圖像的,相信對(duì)這個(gè)框架都不是很陌生,它渲染高級(jí)3D圖形,并使用GPU執(zhí)行數(shù)據(jù)并行計(jì)算。接下來的幾篇我們就詳細(xì)的解析這個(gè)框架。感興趣的看下面幾篇文章。
1. Metal框架詳細(xì)解析(一)—— 基本概覽
2. Metal框架詳細(xì)解析(二) —— 器件和命令(一)
3. Metal框架詳細(xì)解析(三) —— 渲染簡單的2D三角形(一)
4. Metal框架詳細(xì)解析(四) —— 關(guān)于GPU Family 4(一)
5. Metal框架詳細(xì)解析(五) —— 關(guān)于GPU Family 4之關(guān)于Imageblocks(二)
6. Metal框架詳細(xì)解析(六) —— 關(guān)于GPU Family 4之關(guān)于Tile Shading(三)
7. Metal框架詳細(xì)解析(七) —— 關(guān)于GPU Family 4之關(guān)于光柵順序組(四)
8. Metal框架詳細(xì)解析(八) —— 關(guān)于GPU Family 4之關(guān)于增強(qiáng)的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細(xì)解析(九) —— 關(guān)于GPU Family 4之關(guān)于線程組共享(六)
10. Metal框架詳細(xì)解析(十) —— 基本組件(一)
11. Metal框架詳細(xì)解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細(xì)解析(十二) —— 基本組件之器件選擇 - 計(jì)算處理的設(shè)備選擇(三)
13. Metal框架詳細(xì)解析(十三) —— 計(jì)算處理(一)
14. Metal框架詳細(xì)解析(十四) —— 計(jì)算處理之你好,計(jì)算(二)
15. Metal框架詳細(xì)解析(十五) —— 計(jì)算處理之關(guān)于線程和線程組(三)
16. Metal框架詳細(xì)解析(十六) —— 計(jì)算處理之計(jì)算線程組和網(wǎng)格大小(四)
17. Metal框架詳細(xì)解析(十七) —— 工具、分析和調(diào)試(一)
18. Metal框架詳細(xì)解析(十八) —— 工具、分析和調(diào)試之Metal GPU Capture(二)
19. Metal框架詳細(xì)解析(十九) —— 工具、分析和調(diào)試之GPU活動(dòng)監(jiān)視器(三)
20. Metal框架詳細(xì)解析(二十) —— 工具、分析和調(diào)試之關(guān)于Metal著色語言文件名擴(kuò)展名、使用Metal的命令行工具構(gòu)建庫和標(biāo)記Metal對(duì)象和命令(四)
21. Metal框架詳細(xì)解析(二十一) —— 基本課程之基本緩沖區(qū)(一)
Basic Texturing - 基本紋理
演示如何加載圖像數(shù)據(jù)和紋理四邊形。
在Basic Buffers示例中,您學(xué)習(xí)了如何在Metal中渲染基本幾何體。
在此示例中,您將學(xué)習(xí)如何通過將紋理應(yīng)用于單個(gè)四邊形來渲染2D圖像。 特別是,您將學(xué)習(xí)如何配置紋理屬性,解釋紋理坐標(biāo)以及訪問片段函數(shù)中的紋理。
Images and Textures - 圖像和紋理
任何圖形技術(shù)的一個(gè)關(guān)鍵特性是處理和繪制圖像的能力。 Metal以包含圖像數(shù)據(jù)的紋理形式支持此功能。 與常規(guī)2D圖像不同,紋理可以以更具創(chuàng)造性的方式使用,并應(yīng)用于更多表面類型。 例如,紋理可用于替換選定的頂點(diǎn)位置,或者它們可以完全包裹在3D對(duì)象周圍。 在此示例中,圖像數(shù)據(jù)被加載到紋理中,應(yīng)用于單個(gè)四邊形,并呈現(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
類不是此示例的焦點(diǎn),因此不對(duì)其進(jìn)行詳細(xì)討論。 該類演示了基本的圖像加載操作,但不以任何方式使用或依賴于Metal框架。 其唯一目的是便于加載該特定示例的圖像數(shù)據(jù)。
此示例使用TGA
文件格式以簡化。 該文件由描述元數(shù)據(jù)的標(biāo)題(例如圖像尺寸)和圖像數(shù)據(jù)本身組成。 這種文件格式的關(guān)鍵點(diǎn)是圖像數(shù)據(jù)的存儲(chǔ)器布局;特別是每個(gè)像素的布局。
Metal要求使用特定的MTLPixelFormat
值格式化所有紋理。 像素格式描述了每個(gè)紋理像素(其紋理像素)的布局。 要使用圖像數(shù)據(jù)填充Metal紋理,其像素?cái)?shù)據(jù)必須已經(jīng)采用Metal
兼容的像素格式進(jìn)行格式化,該格式由單個(gè)MTLPixelFormat
枚舉值定義。 此示例使用MTLPixelFormatBGRA8Unorm
像素格式,表示每個(gè)像素具有以下內(nèi)存布局:
此像素格式使用每像素32位,按照藍(lán)色,綠色,紅色和alpha順序排列為每個(gè)組件8位。 每個(gè)像素使用32位的TGA
文件已經(jīng)以這種格式排列,因此不需要進(jìn)一步的轉(zhuǎn)換操作。 但是,此示例使用每像素24位BGR
圖像,需要為每個(gè)像素添加額外的8位alpha分量。 由于alpha通常定義圖像的不透明度,并且樣本的圖像完全不透明,因此32位BGRA像素的附加8位alpha分量設(shè)置為255。
在AAPLImage
類加載圖像文件之后,可以通過對(duì)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
對(duì)象用于配置MTLTexture
對(duì)象的紋理尺寸和像素格式等屬性。 然后調(diào)用newTextureWithDescriptor:
方法創(chuàng)建一個(gè)空紋理容器并為紋理數(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];
與存儲(chǔ)多種自定義數(shù)據(jù)的MTLBuffer
對(duì)象不同,MTLTexture
對(duì)象專門用于存儲(chǔ)格式化的圖像數(shù)據(jù)。 盡管MTLTextureDescriptor
對(duì)象指定了足夠的信息來分配紋理內(nèi)存,但還需要其他信息來填充空紋理容器。 通過replaceRegion:mipmapLevel:withBytes:bytesPerRow:
方法用MTLTexture
對(duì)象填充圖像數(shù)據(jù)。
圖像數(shù)據(jù)通常按行組織。 此示例計(jì)算每行的字節(jié)數(shù),即每個(gè)像素的字節(jié)數(shù)乘以圖像寬度。 這種類型的圖像數(shù)據(jù)被認(rèn)為是緊密打包(tightly packed)
的,因?yàn)楹罄m(xù)像素行的數(shù)據(jù)緊跟在前一行之后。
NSUInteger bytesPerRow = 4 * image.width;
紋理具有已知的尺寸,可以解釋為像素區(qū)域。 MTLRegion
結(jié)構(gòu)用于標(biāo)識(shí)紋理的特定區(qū)域。 此示例使用圖像數(shù)據(jù)填充整個(gè)紋理;因此,覆蓋整個(gè)紋理的像素區(qū)域等于紋理的尺寸。
MTLRegion region = {
{ 0, 0, 0 }, // MTLOrigin
{image.width, image.height, 1} // MTLSize
};
注意:要指定紋理的子區(qū)域,
MTLRegion
結(jié)構(gòu)必須具有非零原點(diǎn)值或任何紋理尺寸的較小尺寸值。
每行和特定像素區(qū)域的字節(jié)數(shù)是用于使用圖像數(shù)據(jù)填充空紋理容器的必需參數(shù)。 調(diào)用replaceRegion:mipmapLevel:withBytes:bytesPerRow:
方法通過將image.data.bytes
指針中的數(shù)據(jù)復(fù)制到_texture
對(duì)象來執(zhí)行此操作。
[_texture replaceRegion:region
mipmapLevel:0
withBytes:image.data.bytes
bytesPerRow:bytesPerRow];
Texture Coordinates - 紋理坐標(biāo)
片段函數(shù)的主要任務(wù)是處理傳入的片段數(shù)據(jù)并計(jì)算可繪制像素的顏色值。此示例的目標(biāo)是通過將紋理應(yīng)用于單個(gè)四邊形來顯示屏幕上每個(gè)紋素的顏色。因此,樣本的片段函數(shù)必須能夠讀取每個(gè)紋素并輸出其顏色。
紋理不能單獨(dú)渲染;它必須對(duì)應(yīng)于頂點(diǎn)函數(shù)輸出的一些幾何表面,并由光柵化器變成碎片。此關(guān)系由紋理坐標(biāo)定義:浮點(diǎn)位置,將紋理圖像上的位置映射到幾何表面上的位置。
對(duì)于2D紋理,紋理坐標(biāo)在x和y方向上的值均為0.0到1.0。值(0.0,0.0)
映射到圖像數(shù)據(jù)的第一個(gè)字節(jié)(圖像的左下角)處的紋素。值(1.0,1.0)
映射到圖像數(shù)據(jù)的最后一個(gè)字節(jié)(圖像的右上角)處的紋素。遵循這些規(guī)則,訪問圖像中心的紋素需要指定紋理坐標(biāo)(0.5,0.5)
。
Map the Vertex Texture Coordinates - 映射頂點(diǎn)紋理坐標(biāo)
要渲染完整的2D圖像,必須將包含圖像數(shù)據(jù)的紋理映射到定義2D四邊形的頂點(diǎn)上。 在此示例中,每個(gè)四邊形的頂點(diǎn)指定一個(gè)紋理坐標(biāo),將四邊形的角映射到紋理的角。
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
頂點(diǎn)函數(shù)通過將這些值寫入RasterizerData
輸出結(jié)構(gòu)的textureCoordinate
成員中,沿管道傳遞這些值。 這些值在四邊形的三角形片段中進(jìn)行插值,類似于Hello Triangle樣本中的插值顏色值。
out.textureCoordinate = vertexArray[vertexID].textureCoordinate;
Sample Texels - 示例特征
samplingShader
片段函數(shù)的簽名包括colorTexture
參數(shù),該參數(shù)具有texture2d
類型并使用[[texture(index)]]
屬性限定符。 此參數(shù)是對(duì)MTLTexture
對(duì)象的引用,用于讀取其紋素。
fragment float4
samplingShader(RasterizerData in [[stage_in]],
texture2d<half> colorTexture [[ texture(AAPLTextureIndexBaseColor) ]])
讀取紋素也稱為采樣。 片段函數(shù)使用內(nèi)置紋理sample()
函數(shù)來對(duì)texel
數(shù)據(jù)進(jìn)行采樣。 sample()
函數(shù)有兩個(gè)參數(shù):一個(gè)采樣器(textureSampler)
和一個(gè)紋理坐標(biāo)(in.textureCoordinate)
。 采樣器用于計(jì)算紋理元素的顏色,紋理坐標(biāo)用于定位特定紋理元素。
當(dāng)渲染的區(qū)域與紋理的大小不同時(shí),采樣器可以使用不同的算法來精確計(jì)算sample()
函數(shù)應(yīng)返回的texel
顏色。 mag_filter
模式指定當(dāng)區(qū)域大于紋理大小時(shí),采樣器應(yīng)如何計(jì)算返回的顏色;min_filter
模式指定當(dāng)區(qū)域小于紋理大小時(shí),采樣器應(yīng)如何計(jì)算返回的顏色。 為兩個(gè)濾鏡設(shè)置線性linear
模式可使采樣器平均給定紋理坐標(biāo)周圍的紋素顏色,從而使輸出圖像更平滑。
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
索引來標(biāo)識(shí)Objective-C
和Metal Shading Language
代碼中的紋理。 片段函數(shù)也采用與頂點(diǎn)函數(shù)類似的參數(shù),你可以調(diào)用setFragmentTexture:atIndex:
方法在特定索引處設(shè)置紋理。
[renderEncoder setFragmentTexture:_texture
atIndex:AAPLTextureIndexBaseColor];
在此示例中,您學(xué)習(xí)了如何通過將紋理應(yīng)用于單個(gè)四邊形來渲染2D圖像。
后記
本篇主要講述了基本紋理,感興趣的給個(gè)贊或者關(guān)注~~~