Reputation:
I only need to render 2 dimensional text, but the examples (Text Rendering by MetalByExample.com) I found are in Objective-C, very messy, and probably have a lot of muck (code or steps that aren't necessary for full functionality). How should I go about rendering simple text in Metal? This is trivial in SwiftUI, but how do I do it in Metal? I know this question is kind of vague but there's very little useful resources on how to render simple text in Metal. How could I render a simple hello world text, given this starting code?
import Cocoa
import MetalKit
class ViewController: NSViewController {
private let Device = MTLCreateSystemDefaultDevice()!
private var CommandQue: MTLCommandQueue!, Pipeline: MTLRenderPipelineState!
private var View: MTKView {
return view as! MTKView
}
override func viewDidLoad() {
super.viewDidLoad()
View.delegate = self
View.device = Device
CommandQue = Device.makeCommandQueue()
let PipelineDescriptor = MTLRenderPipelineDescriptor()
let Library = Device.makeDefaultLibrary()!
PipelineDescriptor.vertexFunction = Library.makeFunction(name: "V")
PipelineDescriptor.fragmentFunction = Library.makeFunction(name: "T")
Pipeline = try? Device.makeRenderPipelineState(descriptor: PipelineDescriptor)
}
}
extension ViewController: MTKViewDelegate {
func mtkView(_ _: MTKView, drawableSizeWillChange Size: CGSize) {
View.draw()
}
func draw(in _: MTKView) {
let CommandBuffer = CommandQue.makeCommandBuffer()!, CommandEncoder = CommandBuffer.makeRenderCommandEncoder(descriptor: View.currentRenderPassDescriptor!)!
CommandEncoder.setRenderPipelineState(Pipeline!)
// Render
CommandEncoder.endEncoding()
CommandBuffer.present(View.currentDrawable!)
CommandBuffer.commit()
}
}
Basically how could I replicate this simple SwiftUI in Metal? I'm not asking for a 'code this for me' but I would like some pointers on where to start?
struct ContentView: View {
var body: some View {
Text("Hello, World!")
}
}
Upvotes: 2
Views: 3346
Reputation: 36
I spent two days sourcing simplest implementation so the best for me is to use Alloy pod and converting UILabel to cgImage
func createImage() -> UIImage {
UIGraphicsBeginImageContextWithOptions(
CGSize(width: self.frame.width, height: self.frame.height), true, 1)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
then to mtltexture
context = try! MTLContext(device: Device.shared.device)
let texture = try! context.texture(from: cgImage!,
srgb: false,
usage: [.shaderRead, .shaderWrite])
Upvotes: 0
Reputation: 10418
You can use Core Image's CITextImageGenerator
for that. (There is also CIAttributedTextImageGenerator
for attributed text.)
Just create a CIImage
containing the text and use a CIContext
to render the text into a MTLTexture
(or into the view directly):
// Render
let textImage = CIFilter(name: "CITextImageGenerator", parameters: [
"inputText": "Hello World!",
"inputFontName": "HelveticaNeue",
"inputFontSize": 40,
"inputScaleFactor": 2.0
]).outputImage!
// Note: create the CIContext once and re-use it
self.ciContext.render(textImage, to: View.currentDrawable!, commandBuffer: CommandBuffer, bounds: textImage.extent colorSpace: CGColorSpaceCreateDeviceRGB())
As of macOS 10.15 you can also import CoreImage.CIFilterBuiltins
and use the new protocol-based Core Image interface:
let textImageGenerator = CIFilter.textImageGenerator()
textImageGenerator.text = "Hello World!"
// ...
let textImage = textImageGenerator.outputImage!
If you want to change the color of the text, you can either use the CIAttributedTextImageGenerator
with an attributed string or use more Core Image filters and blending techniques to colorize the text image before rendering it into the view.
Upvotes: 4