[MetalKit]Using MetalKit part 15使用MetalKit15

本系列文章是对 http://metalkit.org 上面MetalKit内容的全面翻译和学习.

MetalKit系统文章目录


第13部分末尾,我们说过让我们的行星看起来更真实有两种方法:添加纹理,或添加一些噪声到plante颜色中.我们在第14部分已经展示了添加噪声.这周我们看看纹理采样.纹理非常有用,因为比起为每个顶点计算颜色,它可以给表面提供更好的细节.

让我们比第13部分Part 13开始,因为我们不再需要噪声代码了.首先,在MetalView.swift中移除mouseDown函数,我们已经不再需要它了.同时移除mouseBufferpos变量,同时移除代码中对它们的引用.然后,创建一个新的纹理对象:

var texture: MTLTexture!

下一步,将这行(可能你已经在前面清理中移除过了):

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

替换为:

commandEncoder.setTexture(texture, atIndex: 1)

同时改变timer的缓冲器索引,从1改为0:

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

我在Resources文件夹添加一张图片名为texture.jpg,你可以用自己的图片代替.让我们创建一个函数来加载并使用这张图片作为纹理:

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函数调用这个函数:

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

现在,清理我们Shaders.metal中的内核,只保留下面几行:

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

你会首次注意到,我们从[[texture(1)]]属性拿到了input纹理,因为这个属性就是我们设置到命令编码器里时的索引.同时,访问权限设置为read.然后我们将其读取到color变量,然而,它却是上下颠倒的.为了修复这个问题,在下一行我们为每个像素反转Y轴.输出图片看起来应该像这样:

chapter15_1.png

如果你打开图片并与我们的输出比较,你会发现它已经旋转到正确朝向了.下一步,我们要找回我们的行星及周围的黑暗天空.用下面一大块代码替换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);

这段代码看起来很熟悉,因为前些章节我们已经讨论过如何创建行星及周围的黑色空间.输出图片看起来应该像这样:

chapter15_2.png

现在很好!下一步我们让行星转动起来.用下面一大块代码替换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);

这段代码看起来又很熟悉,因为前些章节我们已经讨论过如何使用timer让行星动起来.输出图片看起来应该像这样:

chapter15_3.gif

这看起来就比较傻了!输出的图像看起来像一个人举着火把紧贴墙壁走在黑暗的洞穴里.用下面的代码替换最后三行:

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);

首先,我们缩小纹理尺寸到原来的一半,并设置半径为1来匹配行星对象的尺寸和纹理尺寸.然后,神奇的地方来了.让我们引入sampler采样器.sampler采样器是一个包含了各种渲染状态的对象,让纹理来配置:坐标,寻址方式(这里设置为repeat)和过滤方法(设置为linear).下一步,计算球面上每个点的normal法线.最后,我们用采样来计算color而不是像前面一样直接读取.还有一件事要做,在内核参数列表中,让我们也把纹理访问权限由read改为sample.将这一行:

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

替换为:

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

输出图像看起来应该像这样:

chapter15_4.gif

这就是我们所说的真实的行星表面!还要感谢 Chris的帮助.
源代码source code 已发布在Github上.
下次见!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容