Apple Metal 2 4.基礎(chǔ)紋理

原文https://developer.apple.com/documentation/metal/fundamental_lessons/basic_texturing

基本紋理

如何加載圖片數(shù)據(jù) 和 紋理貼圖到正方形.

示例代碼下載

概覽

In the Basic Buffers sample, you learned how to render basic geometry in Metal.
In this sample, you’ll learn how to render a 2D image by applying a texture to a single quad. In particular, you’ll learn how to configure texture properties, interpret texture coordinates, and access a texture in a fragment function.

圖片和紋理

A key feature of any graphics technology is the ability to process and draw images. Metal supports this feature in the form of textures that contain image data. Unlike regular 2D images, textures can be used in more creative ways and applied to more surface types. For example, textures can be used to displace select vertex positions, or they can be completely wrapped around a 3D object. In this sample, image data is loaded into a texture, applied to a single quad, and rendered as a 2D image.

載入圖片數(shù)據(jù)

The Metal framework doesn’t provide API that directly loads image data from a file to a texture. Instead, Metal apps or games rely on custom code or other frameworks, such as Image I/O, MetalKit, UIKit, or AppKit, to handle image files. Metal itself only allocates texture resources and then populates them with image data that was previously loaded into memory.
In this sample, for simplicity, the custom AAPLImage class loads image data from a file (Image.tga) into memory (NSData).

注意:
The AAPLImage class isn’t the focal point of this sample, so it isn’t discussed in detail. The class demonstrates basic image loading operations but doesn’t use or depend on the Metal framework in any way. Its sole purpose is to facilitate loading image data for this particular sample.

This sample uses the TGA file format for its simplicity. The file consists of a header describing metadata, such as the image dimensions, and the image data itself. The key takeaway from this file format is the memory layout of the image data; in particular, the layout of each pixel.
Metal requires all textures to be formatted with a specific MTLPixelFormat value. The pixel format describes the layout of each of the texture’s pixels (its texels). To populate a Metal texture with image data, its pixel data must already be formatted in a Metal-compatible pixel format, defined by a single MTLPixelFormat enumeration value. This sample uses the MTLPixelFormatBGRA8Unorm pixel format, which indicates that each pixel has the following memory layout

This pixel format uses 32 bits per pixel, arranged into 8 bits per component, in blue, green, red, and alpha order. TGA files that use 32 bits per pixel are already arranged in this format, so no further conversion operations are needed. However, this sample uses a 24-bit-per-pixel BGR image that needs an extra 8-bit alpha component added to each pixel. Because alpha typically defines the opacity of an image and the sample’s image is fully opaque, the additional 8-bit alpha component of a 32-bit BGRA pixel is set to 255.
After the AAPLImage class loads an image file, the image data is accessible through a query to the data property.

// Initialize our pointer with source image data that's in BGR form.
uint8_t *srcImageData = ((uint8_t*)fileData.bytes +
                         sizeof(TGAHeader) +
                         tgaInfo->IDSize);

// Initialize our pointer to which we'll store our converted BGRA 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 we're
        //   converting in both the source and destination image arrays
        NSUInteger srcPixelIndex = 3 * (y * _width + x);
        NSUInteger dstPixelIndex = 4 * (y * _width + x);

        // Copy BGR channels from source to destination.
        // Set the alpha channel of our 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;
    }
}

創(chuàng)建紋理

A MTLTextureDescriptor object is used to configure properties such as texture dimensions and pixel format for a MTLTexture object. The newTextureWithDescriptor: method is then called to create an empty texture container and allocate enough memory for the texture data.


MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];

// Indicate that each pixel has a Blue, Green, Red, and Alpha channel,
//    each in an 8 bit unnormalized value (0 maps 0.0 while 255 maps to 1.0)
textureDescriptor.pixelFormat = MTLPixelFormatBGRA8Unorm;
textureDescriptor.width = image.width;
textureDescriptor.height = image.height;

// Create our texture object from the device and our descriptor
_texture = [_device newTextureWithDescriptor:textureDescriptor];

Unlike MTLBuffer objects, which store many kinds of custom data, MTLTexture objects are used specifically to store formatted image data. Although a MTLTextureDescriptor object specifies enough information to allocate texture memory, additional information is needed to populate the empty texture container. A MTLTexture object is populated with image data by the replaceRegion:mipmapLevel:withBytes:bytesPerRow: method.
Image data is typically organized in rows. This sample calculates the number of bytes per row as the number of bytes per pixel multiplied by the image width. This type of image data is considered to be tightly packed because the data of subsequent pixel rows immediately follows the previous row.

NSUInteger bytesPerRow = 4 * image.width;

Textures have known dimensions that can be interpreted as regions of pixels. A MTLRegion structure is used to identify a specific region of a texture. This sample populates the entire texture with image data; therefore, the region of pixels that covers the entire texture is equal to the texture’s dimensions.

MTLRegion region = {
    { 0, 0, 0 },                   // MTLOrigin
    {image.width, image.height, 1} // MTLSize
};

注意:
To specify a subregion of a texture, a MTLRegion structure must have either a nonzero origin value, or a smaller size value for any of the texture’s dimensions.

The number of bytes per row and specific pixel region are required arguments for populating an empty texture container with image data. Calling the replaceRegion:mipmapLevel:withBytes:bytesPerRow: method performs this operation by copying data from the image.data.bytes pointer into the _texture object.

[_texture replaceRegion:region
            mipmapLevel:0
              withBytes:image.data.bytes
            bytesPerRow:bytesPerRow];

紋理坐標(biāo)系

The main task of the fragment function is to process incoming fragment data and calculate a color value for the drawable’s pixels. The goal of this sample is to display the color of each texel on the screen by applying a texture to a single quad. Therefore, the sample’s fragment function must be able to read each texel and output its color.
A texture can’t be rendered on its own; it must correspond to some geometric surface that’s output by the vertex function and turned into fragments by the rasterizer. This relationship is defined by texture coordinates: floating-point positions that map locations on a texture image to locations on a geometric surface.
For 2D textures, texture coordinates are values from 0.0 to 1.0 in both x and y directions. A value of (0.0, 0.0) maps to the texel at the first byte of the image data (the bottom-left corner of the image). A value of (1.0, 1.0) maps to the texel at the last byte of the image data (the top-right corner of the image). Following these rules, accessing the texel in the center of the image requires specifying a texture coordinate of (0.5, 0.5)

映射頂點(diǎn)紋理坐標(biāo)系

To render a complete 2D image, the texture that contains the image data must be mapped onto vertices that define a 2D quad. In this sample, each of the quad’s vertices specifies a texture coordinate that maps the quad’s corners to the texture’s corners.

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 } },
};

The vertexShader
vertex function passes these values along the pipeline by writing them into the textureCoordinate
member of the RasterizerData
output structure. These values are interpolated across the quad’s triangle fragments, similar to the interpolated color values in the Hello Triangle sample.

out.textureCoordinate = vertexArray[vertexID].textureCoordinate;

樣本大小

The signature of the samplingShader fragment function includes the colorTexture argument, which has a texture2d type and uses the [[texture(index)]] attribute qualifier. This argument is a reference to a MTLTexture object and is used to read its texels.

fragment float4
samplingShader(RasterizerData in [[stage_in]],
               texture2d<half> colorTexture [[ texture(AAPLTextureIndexBaseColor) ]])

Reading a texel is also known as sampling. The fragment function uses the built-in texture sample() function to sample texel data. The sample() function takes two arguments: a sampler (textureSampler) and a texture coordinate (in.textureCoordinate). The sampler is used to calculate the color of a texel, and the texture coordinate is used to locate a specific texel.
When the area being rendered to isn’t the same size as the texture, the sampler can use different algorithms to calculate exactly what texel color the sample() function should return. The mag_filter mode specifies how the sampler should calculate the returned color when the area is larger than the size of the texture; the min_filter mode specifies how the sampler should calculate the returned color when the area is smaller than the size of the texture. Setting a linear mode for both filters makes the sampler average the color of texels surrounding the given texture coordinate, resulting in a smoother output image.


constexpr sampler textureSampler (mag_filter::linear,
                                  min_filter::linear);

// Sample the texture and return the color to colorSample
const half4 colorSample = colorTexture.sample (textureSampler, in.textureCoordinate);

設(shè)置片段紋理

This sample uses the AAPLTextureIndexBaseColor index to identify the texture in both Objective-C and Metal Shading Language code. Fragment functions also take arguments similarly to vertex functions: you call the setFragmentTexture:atIndex: method to set a texture at a specific index.

[renderEncoder setFragmentTexture:_texture
                          atIndex:AAPLTextureIndexBaseColor];

接下來(lái)

In this sample, you learned how to render a 2D image by applying a texture to a single quad.
In the Hello Compute sample, you’ll learn how to execute compute-processing workloads in Metal for image processing

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子筝尾,更是在濱河造成了極大的恐慌悲酷,老刑警劉巖授滓,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怒坯,死亡現(xiàn)場(chǎng)離奇詭異忌愚,居然都是意外死亡揩抡,警方通過(guò)查閱死者的電腦和手機(jī)户侥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)峦嗤,“玉大人蕊唐,你說(shuō)我怎么就攤上這事∷干瑁” “怎么了替梨?”我有些...
    開(kāi)封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)装黑。 經(jīng)常有香客問(wèn)我副瀑,道長(zhǎng),這世上最難降的妖魔是什么恋谭? 我笑而不...
    開(kāi)封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任糠睡,我火速辦了婚禮,結(jié)果婚禮上疚颊,老公的妹妹穿的比我還像新娘狈孔。我一直安慰自己,他們只是感情好材义,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布均抽。 她就那樣靜靜地躺著,像睡著了一般母截。 火紅的嫁衣襯著肌膚如雪到忽。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音喘漏,去河邊找鬼护蝶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛翩迈,可吹牛的內(nèi)容都是我干的持灰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼负饲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼堤魁!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起返十,我...
    開(kāi)封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤妥泉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后洞坑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體盲链,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年迟杂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刽沾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡排拷,死狀恐怖侧漓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情监氢,我是刑警寧澤布蔗,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站忙菠,受9級(jí)特大地震影響何鸡,放射性物質(zhì)發(fā)生泄漏纺弊。R本人自食惡果不足惜牛欢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淆游。 院中可真熱鬧傍睹,春花似錦、人聲如沸犹菱。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腊脱。三九已至访得,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悍抑。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工鳄炉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人搜骡。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓拂盯,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親记靡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谈竿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 夜色迷離,華燈初上摸吠。 葉繼晨載著林少白來(lái)到“夜色”酒吧空凸,走進(jìn)他們的預(yù)訂包房,只見(jiàn)紅酒已經(jīng)備好寸痢,還有兩個(gè)衣著暴露的女...
    葉非墨zy閱讀 350評(píng)論 0 1
  • 我有一挎兜斯考奇 你愛(ài)穿那件花外衣 課堂上就喜歡歪著脖兒看你 卻總被老師的粉筆頭兒打斷思緒…… 厚厚一沓的賀年片 ...
    hldcw閱讀 164評(píng)論 0 0
  • 親子日記第8天劫恒,共計(jì)128天。晚上接回大寶轿腺,大寶陪妹妹玩了一會(huì)两嘴。就讓她趕緊把昨天的網(wǎng)上作業(yè)補(bǔ)做了一下。自...
    馨寶貝之快樂(lè)每一天閱讀 198評(píng)論 0 0