user14629932
user14629932

Reputation:

How should I go about rendering text in Metal?

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

Answers (2)

dem.nz
dem.nz

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

Frank Rupprecht
Frank Rupprecht

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

Related Questions