SCNNode большое изображение на фоне вызывает сбой - PullRequest
0 голосов
/ 11 мая 2018

Я пытаюсь создать приложение линейки с ARKit и SceneKit.Я решил создать изображение линейки программно в зависимости от измеренного расстояния.

Вот расширение, которое я использую для рисования линейки:

extension UIImage {

    static let dashLineWidth: CGFloat = 2.0
    static let dashDistance: CGFloat = 163.0 / 25.4
    static let rulerFont: UIFont = .systemFont(ofSize: 15.0, weight: .regular)
    static let attributes: [NSAttributedStringKey: Any] = [
        NSAttributedStringKey.font: rulerFont,
        NSAttributedStringKey.foregroundColor: UIColor.black
    ]

    static func drawRuler(width: CGFloat) -> UIImage? {
        let cm = width * 100 // width in centimeters
        let size = CGSize(width: dashDistance * cm * 10, height: 50.0)

        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }

        let background = UIBezierPath(rect: CGRect(origin: .zero, size: size))
        context.addPath(background.cgPath)
        context.setFillColor(UIColor.white.cgColor)
        context.fillPath()

        var i: CGFloat = 0.0
        var counter: Int = 0
        while i < size.width {
            let isLongDash = counter % 10 == 0
            let isPartDash = counter % 5 == 0
            let dashHeight: CGFloat = size.height * (isLongDash ? 0.25 : isPartDash ? 0.15 : 0.07)
            UIColor.black.setFill()
            UIRectFill(CGRect(x: i - dashLineWidth / 2, y: 0.0, width: dashLineWidth, height: dashHeight))

            if isLongDash && counter != 0 {
                let value = "\(counter / 10)"
                let valueSize: CGSize = value.size(withAttributes: attributes)
                value.draw(at: CGPoint(x: i - dashLineWidth / 2 - valueSize.width / 2, y: dashHeight + 5.0), withAttributes: attributes)
            }

            i += dashDistance
            counter += 1
        }

        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

    func crop(to width: CGFloat, initialWidth: CGFloat) -> UIImage? {
        let rect = CGRect(x: 0, y: 0, width: (width / initialWidth) * size.width * scale, height: size.height * scale)
        guard let croppedCGImage: CGImage = cgImage?.cropping(to: rect) else { return nil }
        return UIImage(cgImage: croppedCGImage)
    }
}

Итак, сначала я рисую 0,5-метровое изображение.только один раз для лучшей производительности, а затем каждый раз, просто обрезая нужную деталь для отображения в SCNNode.

И вот что я пытаюсь в моем SCNNode классе:

var ruler: SCNNode = initRuler()
var initialWidth: CGFloat = 0.5
var rulerImage: UIImage? = UIImage.drawRuler(width: initialWidth)

func updateRuler() {
    guard let geometry = ruler.geometry as? SCNBox else {
        fatalError("Geometry is not SCNBox")
    }
    let width = geometry.width // in meters
    if width > initialWidth - 0.05 {
        initialWidth += 0.5
        rulerImage = UIImage.drawRuler(width: initialWidth)
    }
    guard let croppedImage = rulerImage?.crop(to: width, initialWidth: initialWidth) else { return }
    let texture = SKTexture(image: croppedImage)
    let material = SCNMaterial()
    material.diffuse.contents = texture
    geometry.materials = [material]
}

Всеотлично работает до того момента, когда размер SCNNode становится больше, а изображение тоже больше.Поэтому около 1,3 метра у меня произошел сбой

validateTextureDimensions: 759: сбой утверждения. MTLTextureDescriptor имеет ширину (16501), превышающую максимально допустимый размер 16384. '

Любая помощь будет оценена.Я думал, смогу ли я разделить изображение на части, а затем назначить материал.Или есть другой способ сделать это?

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Вместо того, чтобы устанавливать одно 16501px широкое изображение в одно SCNode, представляющее всю линейку, гораздо более разумно создать вашу линейку из сотен 1cm сегментов, каждый из которых имеет текстуру, которую вы рисуете программно длясегмент линейки с номером.

0 голосов
/ 16 мая 2018

Во-первых, наверное, лучшее, что можно сделать, - это просто найти изображения линейок в Интернете или использовать что-то вроде фотошопа, чтобы сделать свой собственный, потому что делать это программно не очень быстро.Ошибка связана с чем-то, что называется MTLTextureDescriptor, проблема в том, что вы используете большое число, это может быть из-за того, что устройство, на котором вы его запускаете, слишком маленькое, чтобы вместить всю фотографию.

...