[MetalKit]Using MetalKit part 15使用MetalKit15

本系列文章是對(duì) http://metalkit.org 上面MetalKit內(nèi)容的全面翻譯和學(xué)習(xí).

MetalKit系統(tǒng)文章目錄


第13部分末尾,我們說過讓我們的行星看起來更真實(shí)有兩種方法:添加紋理,或添加一些噪聲到plante顏色中.我們?cè)?code>第14部分已經(jīng)展示了添加噪聲.這周我們看看紋理采樣.紋理非常有用,因?yàn)楸绕馂槊總€(gè)頂點(diǎn)計(jì)算顏色,它可以給表面提供更好的細(xì)節(jié).

讓我們比第13部分Part 13開始,因?yàn)槲覀儾辉傩枰肼暣a了.首先,在MetalView.swift中移除mouseDown函數(shù),我們已經(jīng)不再需要它了.同時(shí)移除mouseBufferpos變量,同時(shí)移除代碼中對(duì)它們的引用.然后,創(chuàng)建一個(gè)新的紋理對(duì)象:

var texture: MTLTexture!

下一步,將這行(可能你已經(jīng)在前面清理中移除過了):

commandEncoder.setBuffer(mouseBuffer, offset: 0, atIndex: 2)

替換為:

commandEncoder.setTexture(texture, atIndex: 1)

同時(shí)改變timer的緩沖器索引,從1改為0:

commandEncoder.setBuffer(timerBuffer, offset: 0, atIndex: 0)

我在Resources文件夾添加一張圖片名為texture.jpg,你可以用自己的圖片代替.讓我們創(chuàng)建一個(gè)函數(shù)來加載并使用這張圖片作為紋理:

func setUpTexture() {
    let path = NSBundle.mainBundle().pathForResource("texture", ofType: "jpg")
    let textureLoader = MTKTextureLoader(device: device!)
    texture = try! textureLoader.newTextureWithContentsOfURL(NSURL(fileURLWithPath: path!), options: nil)
}

下一步,在我們的init函數(shù)調(diào)用這個(gè)函數(shù):

override public init(frame frameRect: CGRect, device: MTLDevice?) {
    super.init(frame: frameRect, device: device)
    registerShaders()
    setUpTexture()
}

現(xiàn)在,清理我們Shaders.metal中的內(nèi)核,只保留下面幾行:

kernel void compute(texture2d<float, access::write> output [[texture(0)]],
                    texture2d<float, access::read> input [[texture(1)]],
                    constant float &timer [[buffer(1)]],
                    uint2 gid [[thread_position_in_grid]])
{
    float4 color = input.read(gid);
    gid.y = input.get_height() - gid.y;
    output.write(color, gid);
}

你會(huì)首次注意到,我們從[[texture(1)]]屬性拿到了input紋理,因?yàn)檫@個(gè)屬性就是我們?cè)O(shè)置到命令編碼器里時(shí)的索引.同時(shí),訪問權(quán)限設(shè)置為read.然后我們將其讀取到color變量,然而,它卻是上下顛倒的.為了修復(fù)這個(gè)問題,在下一行我們?yōu)槊總€(gè)像素反轉(zhuǎn)Y軸.輸出圖片看起來應(yīng)該像這樣:

chapter15_1.png

如果你打開圖片并與我們的輸出比較,你會(huì)發(fā)現(xiàn)它已經(jīng)旋轉(zhuǎn)到正確朝向了.下一步,我們要找回我們的行星及周圍的黑暗天空.用下面一大塊代碼替換output行:

int width = input.get_width();
int height = input.get_height();
float2 uv = float2(gid) / float2(width, height);
uv = uv * 2.0 - 1.0;
float radius = 0.5;
float distance = length(uv) - radius;
output.write(distance < 0 ? color : float4(0), gid);

這段代碼看起來很熟悉,因?yàn)榍靶┱鹿?jié)我們已經(jīng)討論過如何創(chuàng)建行星及周圍的黑色空間.輸出圖片看起來應(yīng)該像這樣:

chapter15_2.png

現(xiàn)在很好!下一步我們讓行星轉(zhuǎn)動(dòng)起來.用下面一大塊代碼替換output行:

uv = fmod(float2(gid) + float2(timer * 100, 0), float2(width, height));
color = input.read(uint2(uv));
output.write(distance < 0 ? color : float4(0), gid);

這段代碼看起來又很熟悉,因?yàn)榍靶┱鹿?jié)我們已經(jīng)討論過如何使用timer讓行星動(dòng)起來.輸出圖片看起來應(yīng)該像這樣:

chapter15_3.gif

這看起來就比較傻了!輸出的圖像看起來像一個(gè)人舉著火把緊貼墻壁走在黑暗的洞穴里.用下面的代碼替換最后三行:

uv = uv * 2;
radius = 1;
constexpr sampler textureSampler(coord::normalized,
                                 address::repeat,
                                 min_filter::linear,
                                 mag_filter::linear,
                                 mip_filter::linear );
float3 norm = float3(uv, sqrt(1.0 - dot(uv, uv)));
float pi = 3.14;
float s = atan2( norm.z, norm.x ) / (2 * pi);
float t = asin( norm.y ) / (2 * pi);
t += 0.5;
color = input.sample(textureSampler, float2(s + timer * 0.1, t));
output.write(distance < 0 ? color : float4(0), gid);

首先,我們縮小紋理尺寸到原來的一半,并設(shè)置半徑為1來匹配行星對(duì)象的尺寸和紋理尺寸.然后,神奇的地方來了.讓我們引入sampler采樣器.sampler采樣器是一個(gè)包含了各種渲染狀態(tài)的對(duì)象,讓紋理來配置:坐標(biāo),尋址方式(這里設(shè)置為repeat)和過濾方法(設(shè)置為linear).下一步,計(jì)算球面上每個(gè)點(diǎn)的normal法線.最后,我們用采樣來計(jì)算color而不是像前面一樣直接讀取.還有一件事要做,在內(nèi)核參數(shù)列表中,讓我們也把紋理訪問權(quán)限由read改為sample.將這一行:

texture2d<float, access::read> input [[texture(1)]],

替換為:

texture2d<float, access::sample> input [[texture(1)]],

輸出圖像看起來應(yīng)該像這樣:

chapter15_4.gif

這就是我們所說的真實(shí)的行星表面!還要感謝 Chris的幫助.
源代碼source code 已發(fā)布在Github上.
下次見!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 紋理(Textures) 我們已經(jīng)了解到,我們可以為每個(gè)頂點(diǎn)使用顏色來增加圖形的細(xì)節(jié),從而創(chuàng)建出有趣的圖像。但是通...
    IceMJ閱讀 5,854評(píng)論 2 13
  • 版本記錄 前言 OpenGL 圖形庫項(xiàng)目中一直也沒用過,最近也想學(xué)著使用這個(gè)圖形庫,感覺還是很有意思,也就自然想著...
    刀客傳奇閱讀 9,264評(píng)論 0 8
  • 本系列文章是對(duì) http://metalkit.org 上面MetalKit內(nèi)容的全面翻譯和學(xué)習(xí). MetalKi...
    蘋果API搬運(yùn)工閱讀 319評(píng)論 0 1
  • 立方體貼圖(Cubemap) 我們之前一直使用的是2D紋理,還有更多的紋理類型我們沒有探索過,本教程中我們討論的紋...
    IceMJ閱讀 9,729評(píng)論 2 9
  • 與你相遇,是一種緣分;與你相知,是我的幸運(yùn);但卻因?yàn)槲业哪懬?,我錯(cuò)過了你。 也許,因?yàn)樵?jīng)對(duì)你傾心,所以現(xiàn)在對(duì)你無...
    Kaneki閱讀 141評(píng)論 0 1

友情鏈接更多精彩內(nèi)容