Metal入门资料014,Metal入门资料016

图片 14
ca88会员登录中心

对Metal本领感兴趣的同学,能够关怀作者的专项论题:Metal专辑也得以关怀本人个人的简书账号:张芳涛全体的代码存款和储蓄的Github地址是:Metal

本体系作品是对
http://metalkit.org
上边MetalKit内容的周详翻译和学习.

MetalKit系统小说目录

对Metal手艺感兴趣的同学,能够关怀自己的专项论题:Metal专辑也足以关心自己个人的简书账号:张芳涛全数的代码存储的Github地址是:Metal

让大家来探问第13局部中大家离开的地点。使用大家上次干活的同三个Playground,大家明天将学习照明和3D物体。
还记得大家几周前做过的日食吗? 它回到了!
行吗,大家要去除太阳,此番只关怀地球。


在第14局地的尾声,大家得出结论,大家得以通过两种方法使大家的繁星看起来更逼真:要么对其采取纹理,要么为行星颜色增加一些噪点。
我们体现了怎样在第15有的中增添噪点。接下来大家将根本介绍纹理和采集样品器。
纹理是平价的,因为它们可感到表面提供比每一个终端的水彩计算越来越高品位的内部原因。

先是,让我们清理大家的内核只包涵这么些代码:

让大家从第12局地 Part
12继续.使用上次我们做事的同贰个playground,大家今日将学习光照和3D物体.记得前几周大家做出的日食吗?它又回到了!
好啊,此次大家将移除太阳,只关切行星.

让大家从第14部分中的地点上马,因为此番大家无需噪声代码。
首先,在MetalView.swift中,让大家删除mouseDown函数,因为大家不再需求它了。
同一时间删除mouseBufferpos变量,以及代码中对它们的别样引用。
然后,创建七个新的纹路对象:

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

首先,让大家清理内核,使其只含有上边的代码:

var texture: MTLTexture!

多少个礼拜前您肯定会认出这么些代码。
大家唯一做的是用墨绛红替换外圈颜色,用粉红替换内圈颜色。
输出图像应如下所示:

int width = output.get_width();
int height = output.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 ? float4(1) : float4(0), gid);

接下去,替换下边包车型大巴代码:

图片 1效果图

您显明认出几周前的这一个代码了.大家惟一改观的是将圆外面包车型大巴颜料替换为黑色,并将圆内部改为白色.输出的糊涂应该是以此样子:

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

到今天长逝还蛮好。 那几个星球看起来很平整,照明布满太均匀,看起来空头支票。
大家接下去消除那几个主题材料啊。
几何学告诉大家,为了找到球体上的任何点,大家要求球体方程:

图片 2

用如下的代码:

^2 + ^2 + ^2 = r^2

chapter13_0.png

commandEncoder.setTexture(texture, atIndex: 1)

在大家的出格情状下,x0,y0和z0都以0,因为我们的圆球位于显示屏的主导。
求解z提交了行星颜色的值,所以让我们用这么些行替换内核中的最后一行:

现阶段可以接受.行星看起来相当扁平,光照布满的太均匀看起来荒诞不经.让自家接下去修复它.几何学告诉大家,为了找到球面上的点,我们必要球体公式:

并将大家的计时器的缓冲区索引从1更改为0

float planet = float(sqrt(radius * radius - uv.x * uv.x - uv.y * uv.y));planet /= radius;output.write(distance < 0 ? float4 : float4;

图片 3

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

体现的成效如下:

chapter13_2.png

我在PlaygroundResources文本夹中增添了叁个名称叫texture.jpg的图像,但假若必要,能够增加你的图像。
让我们制造一个选择此图像设置或纹理的函数:

图片 4效果图

在我们的例子中,x0,
y0z0都是0因为大家的圆球在显示屏中间.算出z值就足以博得planet行星颜色的值,所以让大家用上边这几行来替换内核中的最终一行:

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

正如您所料,以往测算的水彩从圆心起初以全金黄初步,在外圆上以全黑甘休。
为了达成那一点,大家只好将颜色除以半径,以便将大家的限定规范化为z值的[0,1]区间,进而为大家提供全范围的光效。
我们实际上假装光源位于`。 这引出了下一个主题:lighting`。

float planet = float(sqrt(radius * radius - uv.x * uv.x - uv.y * uv.y));
planet /= radius;
output.write(distance < 0 ? float4(planet) : float4(0), gid);

接下来,在init函数中调用此函数:

Lighting是给予大家色彩生命的事物。
为了在场景中有灯的亮光,大家须求总计各种坐标的’normal’。
法线向量在表面上垂直,向大家展示表面在每一种坐标处“指向”的岗位。
用那几个行替换最后两行:

出口图像应该像起来像那样:

override public init(frame frameRect: CGRect, device: MTLDevice?) {super.init(frame: frameRect, device: device)registerShaders()setUpTexture()}
float3 normal = normalize(float3(uv.x, uv.y, planet));output.write(distance < 0 ? float4(float3, 1) : float4;

图片 5

近些日子,让我们在Shaders.metal中清理大家的水源,只包含那一个行:

请小心,大家曾在行星变量中获取了z的值。 输出图像应如下所示:

chapter13_1.png

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

图片 6效果图

正如您愿意的那么,颜色从中路的纯深紫红变为圆外面包车型地铁纯高粱红.为此,大家必需用颜色除以radius半径,来使z值规范化到[0,1]间隔内,它能给大家全范围的光照效果.大家实际上伪造了二个电灯的光源放在(0,0,1).让引出了新话题:lighting灯光.

您将率先注意到大家通过[[texture]]本性获取输入纹理,因为那是大家在指令编码器中装置它的目录。
其它,还有也许会读取我们呼吁的拜谒权限。
然后大家将它读入颜色变量,但是,它反过来倒置。
为了缓和这么些难题,在下一行大家只需翻转各样像素的Y坐标。
输出图像应如下所示:

那只怕不是我们想要看到的,但最少我们今后精通在测算各样标准化坐标处的颜料时法线是怎么样的。
接下来,让大家创建二个放在右边和稍后任务的光源。 用那么些行替换最终一行:

lighting灯光让大家的颜料真正活起来.为了在大家的地方中有三个电灯的光,大家必要总括各个坐标的normal法线.法向量是垂直于表面,告诉大家外表”指向”哪个坐标.用上面几行替换最终3000:

图片 7效果图

float3 source = normalize(float3);float light = dot(normal, source);output.write(distance < 0 ? float4(float3, 1) : float4;
float3 normal = normalize(float3(uv.x, uv.y, planet));
output.write(distance < 0 ? float4(float3(normal), 1) : float4(0), gid);

万一张开图像并将其与输出进行相比较,您会发觉它未来已正确定位。
接下来,大家想要带回大家的星辰和它周边的莲红天空。
用那几个代码块替换输出游:

咱俩采纳了一种叫做Lambertian光的基本光模型,大家必要将法线与准则光源相乘。
大家就要现在的小说中详细研商Lighting,然而,如若你有乐趣精晓有照料明模型的越来越多音讯,这里有一个很好的能源供你参谋。
输出图像应如下所示:

注意,我们在planet行星变量中早就有z值了.输出的图片看起来应当那样:

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

图片 8效果图

图片 9

这段代码看起来很熟识,因为大家早就在前边的章节中商量了怎么成立行星及其左近的月光蓝空间。
输出图像应如下所示:

还记得上次大家的根本还给大家多个统一的电磁照望计时器吗? 用这几个替换源代码行:

chapter13_5.png

图片 10效果图

float3 source = normalize(float3(cos, sin, 1));

那可能不是我们想要看到的,但最少大家精通在每一个规格化坐标处总括颜色时法线看起来是何等样子了.下一步,让大家创造一个光源放置在大家左边(负x),后面(正z)一点.用下边几行替换最终一行:

到以后甘休还蛮好! 咱们接下去想让咱们的星星再一次转动。
用这几个代码块替换输出游:

通过运用cossin函数,大家给光源三个圆圆的运动。
使用圆的参数方程,xy都在-11的限制内。 输出图像应如下所示:

float3 source = normalize(float3(-1, 0, 1));
float light = dot(normal, source);
output.write(distance < 0 ? float4(float3(light), 1) : float4(0), gid); 
uv = fmod(float2 + float2(timer * 100, 0), float2(width, height));color = input.read);output.write(distance < 0 ? color : float4;

图片 11效果图

大家利用了一种基本的光照模型叫做朗Bert
Lambertian(漫反射)光照,在那之中大家将法线乘以规格化光源.我们就要之后的稿子中上学越来越多光照知识,然而要是您对学习光照模型很有意思味,能够参照这里
here的大多能源.输出的图纸看起来应当如此:

这段代码在前几章中重复看起来很熟识,大家探究了怎么采纳反应计时器为地球制作动画。
输出图像应如下所示:

大家什么样在场景中看到美丽的照明物体,不过,物体依旧展现出均匀的外表。
我们能够通过三种方法使其看起来更逼真:要么对其采取纹理,要么为行星颜色增多一些噪点。
源代码点击本人

图片 12

![效果图](https://upload-images.jianshu.io/upload_images/661949-a2dc0936c21c9d78.gif?imageMogr2/auto-orient/strip)

chapter13_3.png

那有一点点窘迫! 输出看起来像高光灯。 用这段代码替换我们增多的最后三行:

还记得上一回基本给大家了一个放大计时器uniform吗?让大家用起来玩玩!用那行替换source行:

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;float pi = 3.14;float s = atan2( norm.z, norm.x ) / ;float t = asin / ;t += 0.5;color = input.sample(textureSampler, float2(s + timer * 0.1, t));output.write(distance < 0 ? color : float4;
float3 source = normalize(float3(cos(timer), sin(timer), 1));

首先,我们缩短到纹理大小的八分之四并将半径设置为1,那样大家就可以将行星对象大小与纹理大小相相配。
然后是玄妙的。 让自家介绍一下采样器。
采集样品器是含有纹理供给配备的各样渲染状态的靶子:其坐标,寻址方式和滤波方法。
接下来,我们总计球体上各个点的法线,然后利用法线计算球体周边的角度。
最终,大家因此采集样品来总括颜色,实际不是像从前那样读取颜色。
还会有一件事要做。
在基础参数列表中,让大家重新配置对sample的纹理访问实际不是read
替换上面包车型客车代码:

经过行使cossin函数,大家给光源一个圆圆的运动.xy都以按圆的参数方程从-11.输出的图形看起来应当那样:

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

图片 13

用如下代码:

chapter13_6.gif

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

小编们来留心看看,场景中的物体被照亮(天空中的行星),可是,物体依然展现出单一的表面.大家有两种方法能够让它看起来更诚实:使用纹理,恐怕给plante颜色加上有个别噪点.
源代码source
code
已宣布在Github上.
下次见!

出口图像应如下所示:

图片 14末段效果

代码在那边

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图