Tag: 金属

使用新的iOS 10 SceneKit惊人的基于物理的渲染

毫无疑问,在移动设备上进行渲染时,Apple已开始使用它。 实时渲染和高级硬件的最新进展确实为获得高端结果提供了机会,而无需在设备上花费2000美元的价格。 尽管Apple的团队在WWDC 16’上介绍了许多进步,但是我真正注意到了一项改进,那就是SceneKit中基于物理渲染(PBR)的支持。 在过去的几年中,这种渲染技术获得了广泛的关注,并已成为工程师和3D艺术家的事实上的行业标准。 在这篇简短的文章中,我将尝试演示如何简单地使用新推出的iOS 10基于物理的渲染器,并在不具有任何高级图形引擎复杂性的情况下获得出色的效果。 在继续之前,我想坦诚地声明。 本文过度简化了一些概念,以使您对PBR中的关键元素有所了解。 基于物理的渲染 重要的是要了解不同的环境贴图会创建非常不同的渲染,因此请仔细选择您的环境贴图。 选择正确的环境图本身就是一门艺术,通常是由经验丰富的3D艺术家完成的。 物理渲染的材质定义 材料对于出色的PBR着色至关重要。 它们为我们的着色器提供了使这些惊人的可视化效果的基本信息。 过去,定义材料非常困难。 有上百万个参数需要调整,并且需要大量的魔术师和经验来使它正确。 此外,材料定义与照明非常相关,这在材料创建方面造成了问题。 使用PBR阴影,故事变得简单得多。 实际上,仅使用两个浮点数就可以很容易地获得视觉上令人愉悦的陶瓷,塑料或金属(请参见下文)。 基本上,您可能会达到相同的外观和感觉,但是艺术家将不得不工作几个小时才能获得他们想要的精美外观。 PBR材料的三个主要参数称为: 反照率,粗糙度和金属度 。 反照率分量是对象的基础颜色,并且与其他着色模型的漫反射分量直接相关。 反照率值通常是RGB颜色,通常由3个浮点数定义。 粗糙度和金属度 – 这些值描述了表面的粗糙度或金属感。 下图很好地说明了仅使用0.0-1.0范围内的浮点值来更改任一值对渲染结果的影响。 为了获得专业的效果,您将需要使用纹理,该纹理将为模型上的每个点定义不同的PBR组件。 幸运的是,大多数3D艺术家已经熟悉此着色模型,并发布了免费的材质定义,可以帮助您快速启动任何项目。 此外,iOS 10 PBR材质还支持其他贴图,例如法线贴图,这些贴图是可选的,但必须使用以获得良好的外观。 为了演示的目的,我使用了freepbr.com的一些资料。 如果要使用其他材料测试代码(如下),请确保将其签出。 编码时间 我们将一起创建旋转球的示例,如下所示。 无需担心-所有代码都在GitHub上发布。 首先,您需要了解一些先决条件: 获得可用的最新macOS,iOS和Xcode beta版本-您不想因为Apple已经解决的错误而陷入困境。 不要使用模拟器-始终使用支持金属的设备。 这是Beta版软件-可能也会出现错误 准备看它有多简单? 我们走吧 我假设您有编写Swift代码的经验,并且您已经创建了一个SceneKit视图。 如果还没有,请从Game模板开始,然后选择SceneKit作为您的游戏技术。 您将获得的模板代码足以完成本练习(我在这里实际使用过……) 第一步:创建一个场景: 让场景= SCNScene(名称:“ sphere.obj”)! 如您所见,直接从OBJ文件初始化场景非常简单。 […]

Metal Camera教程奖金:在iOS Simulator中运行Metal项目

在《金属相机教程》系列中,我们创建了一个简单的应用程序,可以在屏幕上实时渲染相机帧。 但是,此应用程序使用的是Metal框架,iOS模拟器中没有该框架。 基本上,如果您选择模拟器作为构建设备,则您的应用甚至都无法构建,这很可惜,例如,要添加单元测试,而无需在未将实际设备连接到计算机的情况下就可以运行它们。 Metal某些部分具有针对桌面处理器体系结构的存根实现,这意味着您至少可以构建该应用程序(仅是发现它在模拟器上无法正常工作)。 Simulator甚至不存在其他部件,例如MetalKit ,因此您必须将导入包装到条件编译块中,如下所示: import UIKit import Metal #if arch(i386) || arch(x86_64) #else import MetalKit #endif 我们检查当前的处理器体系结构是否为台式机,在这种情况下根本不导入任何仅ARM的框架。 请注意, MetalKit中的类也不可用,因此您也需要使用它们包装任何代码: public class MTKViewController: UIViewController { #if arch(i386) || arch(x86_64) #else /// `UIViewController`’s view private var metalView: MTKView! #endif // MARK: – Public overrides override public func loadView() { super.loadView() #if arch(i386) || arch(x86_64) NSLog(“Failed […]

迅捷金属乐

适用于iOS和macOS的超快速着色器和管线探索 在过去的几年中,与许多开发人员一样,在Swift Playgrounds中工作时,我对编辑/编译/运行周期的速度不满意。 Swift Playgrounds让我们有机会轻松编写快速代码以测试概念,而无需构建完整的应用程序,部署到设备或模拟器以及观察结果。 我已使用Swift Playgrounds更好地了解了许多技术,包括: 斯威夫特语言概念 核心动画 SpriteKit 场景套件 一个让我难以理解的领域是在Swift Playground的Metal中工作。 Metal是Apple的底层图形系统,旨在利用自己的硬件并提供出色的性能。 我相当怀疑是否有直接在Metal中工作的实际输出-SceneKit对我来说做得很好-但我仍然感到需要挠痒痒。 因此,另一个游乐场冒险开始了。 配置游乐场 在创建用于Metal开发的游乐场时,需要将其设置为macOS游乐场。 iOS操场不符合条件,因为模拟器无法提供我们进行Metal开发所需的直接GPU访问。 我们需要导入一些框架。 为了处理我们的macOS视图,我们需要访问Cocoa。 我们需要Metal才能与Metal合作。 最后,我们需要PlaygroundSupport才能显示Metal视图。

带金属的核心图像滤镜

我们可以创建在iOS 11或更高版本中以金属阴影语言(MSL)编写的自定义核心图像滤镜。 在A8或更高版本的设备上受支持。 它可以在构建时进行预编译,因此可以获得更好的性能。 现有方法(GLSL或CIKernel语言)在运行时进行编译。 以下是添加到CIKernel的新API: 公共便利init(functionName名称:字符串,fromMetalLibraryData数据:数据)引发公共便利init(functionName名称:字符串,fromMetalLibraryData数据:数据,outputPixelFormat格式:CIFormat)引发 这是CIColorKernel的简单MSL实现: #include 使用命名空间金属; #include //包含CIKernelMetalLib.h extern“ C” {名称空间coreimage { float4 myColor(sample_t s){ 返回s.grba; } }} 让我们将其另存为kernel.metal或其他名称(任何名称都可以,但是扩展名应该是.metal )。 可以使用新的API初始化使用着色器功能的CIColorKernel : 让url = Bundle.main.url(forResource:“ default”,withExtension:“ metallib”)! 让数据=尝试! 数据(contentsOf:url) 让内核=尝试! CIColorKernel(functionName:“ myColor”,fromMetalLibraryData:data) 因此,可以像这样实现具有自定义内核的CIFilter子类: 导入CoreImage MetalFilter类:CIFilter { 专用let内核:CIColorKernel var inputImage:CIImage? 覆盖init(){ 让url = Bundle.main.url(forResource:“ default”,withExtension:“ metallib”)! 让数据=尝试! 数据(contentsOf:url) 内核=试试! CIColorKernel(functionName:“ myColor”,fromMetalLibraryData:data) super.init() […]

通过共享资源内存来结合CoreGraphics和Metal的功能

Metal API很棒,它为移动设备和台式设备打开了很多可能性。 但是, GPU有时可能有点笨拙,尤其是在诸如字体渲染或曲线绘制之类的高精度项目中,因此有时您确实会错过旧的CPU优秀项目。 我经常碰巧会想使用CoreGraphics的一些功能,但是保持我的GPU管道快速高效,而没有多余的转换或CPU / GPU同步中断 。 启发我写这篇文章的情况是,使用户能够绘制遮罩覆盖图,以识别希望显示某些效果的区域。 当然可以用Metal来实现绘图,但这需要大量工作:保持路径数据,三角剖分和渲染逻辑。 对于快速原型,仅使用CoreGraphics会容易得多,但是最直接的方法是从UI画布创建CGImage ,然后转换为MTLTexture以将其作为遮罩提供给某些着色器。 多维门户 但是,如果我们希望避免不必要的转换并将CoreGraphics路径直接绘制到MTLTexture中怎么办 ? 这似乎完全有可能! 为了实现这一点,我们必须在某些CGContext和MTLTexture之间共享一个内存缓冲区。 Metal可以从MTLBuffer对象创建纹理,而MTLBuffer则有机会指向已分配的内存。 因此,我们需要执行以下操作: 为CGContext分配内存 创建指向相同内存的MTLBuffer 从MTLBuffer创建MTLTexture 瞧! 实施 免责声明#1:在此演示中,我使用Alloy ,这是我在Apple平台上所有GPU项目中使用的Metal库。 它在香草金属上提供了一个很小的Swifty API 免责声明2:我既不在演示中也不做任何分解,也没有错误处理。 一切都在视图控制器中完成,无论是强制展开还是致命错误。 本文用作参考片段。 当为MTLBuffer分配无副本内存时,事情有些棘手。 为了使其快乐,它必须完美对齐 ,通常为4096字节。 在创建MTLBuffer时, MTLTextures也很麻烦 :我们必须对齐每个纹理行 ,并且对齐方式取决于我们要使用的像素格式 。 幸运的是,这两个任务都是可行的! 为了演示起见,我们将为MTKView上的可绘制单通道蒙版分配共享资源。 每当我们的MTKView更改大小时,我们都会重新分配掩码。 当然不是必须的,但这是最简单的方法。 首先,我们需要从系统中了解RAM页面大小,因此,我们将使用getpagesize()函数。 现在我们必须计算每行对齐的字节数和总分配大小。 为了分配对齐的内存,我们将使用posix_memalign(_,_,_)系统函数。 请注意,从这一点来看,我们负责分配此内存,但是稍后我们将对其进行处理 现在我们准备从此内存创建CGContext ,您可能已经完成了很多次,因此这应该非常简单: 我在这里使用CGImageAlphaInfo.no​​ne表示这是灰度图像,但是您也可以使用.alphaOnly 使用完全相同的内存,我们现在可以创建一个无副本MTLBuffer ,使其负责释放内存。 但是,您当然可以通过将nil传递给最后一个参数来自行管理。 现在,最后一步:我们正在从此缓冲区创建纹理。 纹理的存储模式必须与缓冲区相同。 […]