晚香玉 - 基于苹果Metal构建的3D图形框架
👋
关于晚香玉是一个3D图形框架(受threejs启发),它帮助设计师和开发者与苹果的Metal API一起工作。晚香玉提供了创建网格、材料、缓冲区、统一变量、几何体、管道(着色器)、计算核心等有用的类,并将它们渲染到屏幕或纹理上。
晚香玉使简单的图形任务变得有趣且易于快速完成,同时使复杂的图形任务更容易完成,而无需编写大量样板代码。它通过提供结构、观点以及在Metal上提供许多有用的抽象来做到这一点,以帮助您在几分钟内开始渲染/编码。
晚香玉主要基于Swift编写,然而当进行昂贵的CPU操作时,晚香玉使用SatinCore,它是用C编写的(用于几何生成、三角化、边界和计算几何计算等任务),以确保尽可能快。
✨
示例
⚙️
要求- macOS 10.15。
- Xcode 11.0。
- Swift 5.0。
💻 📱 📺
支持的平台- macOS 10.15。
- iOS 13.0.
- tvOS 13.0.
安装
Swift Package Manager
Swift Package Manager 是一个用于自动分发 Swift 代码的工具,并集成到 Swift
编译器中。一旦您设置了 Swift 包,添加 Satin
作为依赖项就像将其添加到 Package.swift
的 dependencies
值一样简单。
dependencies: [
.package(url: "https://github.com/Hi-Rez/Satin.git", .branch("master"))
]
CocoaPods
CocoaPods 是 Cocoa 项目的集中式依赖管理器。有关使用和安装说明,请访问他们的网站。要使用 CocoaPods 将 Satin
集成到您的 Xcode 项目中,请在 Podfile
中指定它。
pod 'Satin'
📋
功能- 大量示例,展示如何使用 API(2D、3D、光线追踪、计算、导出、实时编码、AR 等)。
- 对象、网格、材质、着色器、几何形状和渲染器类。
- 您可以实时编写着色器
🔥 . - 一些内置的材质(基础颜色、基础纹理、基础漫反射、法线、UV 颜色、天空盒、MatCap 等)。
- 大量几何形状(盒子、球体、IcoSphere、圆形、圆锥体、四边形、平面、胶囊、圆角矩形、文本等)。
- 摄像机(正交、透视)。
- 2D 和 3D 摄像机控制器。
- 通过参数使用缓冲区和统一变量创建实时和动态结构。
- 金属着色器编译器(实时编码时很有用),用于 LiveShader(在 LiveMaterial 中使用)。
- 用于高速处理数据的缓冲区和纹理计算系统。
- 快速的GPU光线投射器(非常有助于查看您点击或轻触的位置)。
- 自定义Metal渲染钩子:Mesh的preDraw、Material的onBind、Buffer & Texture Computes的preCompute等
- FileWatcher用于检查资源或着色器文件是否已更改。
🚀
用法Satin帮助在Metal支持的视图中绘制事物。为了快速启动并运行,而不需要大量样板代码,也不必担心三缓冲或事件(设置、更新、调整大小、键盘、鼠标、触摸)回调,Satin与Forge配合良好,但也可以单独使用。下面的示例显示了如何协同使用Forge & Satin来渲染一个查看场景中移动点的颜色变化的盒子。
简单示例
import SwiftUI
import MetalKit
import Forge
import Satin
// Subclass Forge's Renderer to get triple buffered rendering and
// callbacks for Setup, Update, Draw, Resize and Events
class SimpleRenderer: Forge.Renderer {
// A Context contains important information that is needed to help compile shaders
// and ensure we are drawing with the right color and depth pixel formats and sample count
var context: Context!
// A Satin Renderer handles setting the Content on all the objects in the scene graph
// and drawing the scene either to a texture or on screen
var renderer: Satin.Renderer!
// A PerspectiveCamera is used to render the scene using perspective projection
// All Satin Cameras inherit from Object, so it has
var camera: PerspectiveCamera!
// An Object is just an empty node in Satin's Scene Graph, it can have children and a parent
// Objects have a position, orientation, scale and label
var scene: Object = Object("Scene")
// Meshes inherit from Object, so they have all the properties an object has.
// A Mesh has unique properties like geometry, material and rendering properties
// To create renderable object aka a Mesh, you passing it a Geometry and Material like so
var boxMesh = Mesh(geometry: BoxGeometry(size: 1.0), material: BasicDiffuseMaterial(0.75))
// Create a time variable so we can change things in our scene over time
var time: Float = 0.0
// Forge calls setup once after it has a valid MTKView (mtkView)
override func setup() {
// Forge's Renderer class provides a MTLDevice and convenience getters for the view's color pixel format,
// depth pixel format and stencil pixel format, by default a Forge Renderer has depth
context = Context(device, sampleCount, colorPixelFormat, depthPixelFormat, stencilPixelFormat)
// When creating a camera, you can specify an initial position and the near and far plane values
camera = PerspectiveCamera(position: [0.0, 0.0, 5.0], near: 0.01, far: 100.0)
// Create a Satin Renderer by passing in a context, scene and camera
renderer = Satin.Renderer(context: context, scene: scene, camera: camera)
// There are many properties you can set on the renderer, this is how to clear to white
renderer.setClearColor([1, 1, 1, 1])
//Finally add the box mesh created above to the scene
scene.add(boxMesh)
}
// Forge calls update whenever a new frame is ready to be updated, make scene changes here
override func update() {
// We increment our time variable so we can procedurally set the box mesh's orientation and material color
time += 0.05
let sx = sin(time)
let sy = cos(time)
// Setting a material property done by using the set function, this modifies the material's uniforms
boxMesh.material?.set("Color", [abs(sx), abs(sy), abs(sx + sy), 1.0])
// You can manually an object's position, orientation, scale, and localMatrix. Here I'm using a
// convenience lookAt function to orient the box to face the point passed from its current position
boxMesh.lookAt([sx, sy, 2.0])
}
// Forge calls draw when a new frame is ready to be encoded for drawing
override func draw(_ view: MTKView, _ commandBuffer: MTLCommandBuffer) {
guard let renderPassDescriptor = view.currentRenderPassDescriptor else { return }
// To render a scene into a render pass, just call draw and pass in the render pass descriptor
// You can also specify a render target and render to a texture instead
renderer.draw(renderPassDescriptor: renderPassDescriptor, commandBuffer: commandBuffer)
}
// Forge calls resize whenever the view is resized
override func resize(_ size: (width: Float, height: Float)) {
// whenever the screen is resized we need to make sure:
// our camera's aspect ratio is set
camera.aspect = size.width / size.height
// our renderer's viewport & texture sizes are set
renderer.resize(size)
// if you need to render to a custom viewport, you can specify that after the resize call:
// renderer.viewport = MTLViewport(...)
}
}
// Using SwiftUI you can use a ForgeView to easily create a MTKView and pass in a Forge.Renderer
struct ContentView: View {
var body: some View {
ForgeView(renderer: SimpleRenderer())
}
}
待办事项
- 更多文档
- 实例化网格
- 线网格
- 基于物理的着色、光照、阴影
- SDF文本渲染
- 圆角Box几何结构
- 灵活的顶点结构
- 光线追踪计算系统
🎉
贡献
💬
行为准则保持友好。没有愚蠢的问题。
😎
致谢Satin 由 Reza Ali 拥有并维护。你可以在 Twitter 上关注我 @rezaali,或通过 邮件 联系我以获得项目更新、发布和问题。
🙌
支持Satin 是一项充满爱心的劳动成果,精心制作,使用方便,快速友好。如果您在使用项目中使用 Satin,请考虑支持该项目。以前的赞助商包括:The Frank-Ratchye STUDIO for Creative Inquiry。
🎓
许可Satin 根据 MIT 许可证发布。有关详细信息,请参阅 LICENSE。