Статьи

FurrySketch: Рисование Hirsute с Apple, карандаш

После  моих недавних  (неправильных) экспериментов с использованием моего Apple Pencil для гнусного и альтернативного использования, я подумал, что пора поиграть с Pencil по его прямому назначению, рисованию эскизов, и посмотреть, как я могу использовать его данные ориентации для воздействия на мазки кисти. 

FurrySketch  — это приложение для рисования на основе карандаша, которое рисует своего рода разноцветные волосы, и, что самое интересное, направление волос соответствует углу карандаша. Это было очень просто написать и, по крайней мере, на мой взгляд, дает действительно хорошие результаты.

Основная механика взята из моего   проекта ForceSketch : я использую CIImageAccumulator с каждым новым растровым изображением (созданным внутри touchesMoved), скомпонованным поверх ранее накопленных изображений с фильтром Core Image CISourceOverCompositing.  

Интересная часть для поклонников Карандаша — создание волосатых мазков кисти:

Hirsute Brush Mechanics

Внутри штрихов, перемещенных, я зацикливаюсь на слитых касаниях (о слипшихся касаниях вы можете прочитать в моем   блоге Advanced Touch Handling ). Для каждого из промежуточных касаний я хочу найти его местоположение на виде, угол высоты и вектор азимута. Этот вектор указывает в направлении угла азимута карандаша, и, умножив его на нормализованный угол высоты, я получаю смещение, которое можно использовать при рисовании моих маленьких волосков:

for coalescedTouch in coalescedTouces
    {
        let touchLocation = coalescedTouch.locationInView(view)

        let normalisedAlititudeAngle =  (halfPi - touch.altitudeAngle) / halfPi
        let dx = coalescedTouch.azimuthUnitVectorInView(view).dx * 20 * normalisedAlititudeAngle
        let dy = coalescedTouch.azimuthUnitVectorInView(view).dy * 20 * normalisedAlititudeAngle

Затем я использую силу прикосновения, чтобы решить, сколько волосков нарисовать …

    let count = 10 + Int((coalescedTouch.force / coalescedTouch.maximumPossibleForce) * 100)

Теперь я повторяю счетчик раз. На каждой итерации я создаю случайный угол и создаю константы для внутреннего радиуса и начальной точки для каждого волоса:

    let innerRandomRadius = drand48() * 20
    let innerRandomX = CGFloat(sin(randomAngle) * innerRandomRadius)

    let innerRandomY = CGFloat(cos(randomAngle) * innerRandomRadius)

Хотя начальная точка волос не зависит от ориентации карандаша, конечная точка -. Здесь я создаю другой, больший, случайный радиус, использую тот же угол и смещаю конечную точку на dx и dy, которые я создал выше:

 randomRadius = innerRandomRadius + drand48() * 40 * Double(normalisedAlititudeAngle)
    let outerRandomX = CGFloat(sin(randomAngle) * outerRandomRadius) - dx

    let outerRandomY = CGFloat(cos(randomAngle) * outerRandomRadius) - dy

С этими значениями я могу нарисовать волосы в моем контексте и повторить:

    CGContextMoveToPoint(cgContext,
        touchLocation.x + innerRandomX,
        touchLocation.y + innerRandomY)

    CGContextAddLineToPoint(cgContext,
        touchLocation.x + outerRandomX,
        touchLocation.y + outerRandomY)


    CGContextStrokePath(cgContext)

Быстрое напоминание о CIImageAccumulator: после завершения большого волосатого цикла я могу получить вновь сгенерированное изображение из контекста и использовать фильтр CISourceOverCompositing, чтобы скомпоновать это изображение для этого касания, переместить поверх предыдущего и, наконец, отобразить его в UIImageView:

 let drawnImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    compositeFilter.setValue(CIImage(image: drawnImage),
        forKey: kCIInputImageKey)
    compositeFilter.setValue(imageAccumulator.image(),
        forKey: kCIInputBackgroundImageKey)

    imageAccumulator.setImage(compositeFilter.valueForKey(kCIOutputImageKey) as! CIImage)


    imageView.image = UIImage(CIImage: imageAccumulator.image())

В заключении

If you are writing drawing apps, adding Pencil support is not only super easy, it adds real value for your users. The technique I’ve used here to draw hair is only a few lines of code way from spray cans and air brushes and I genuinely believe the iPad Pro will prove to be an amazing device for creatives.

As always, the source code for this project is available at my GitHub repository here. Enjoy and happy Thanksgiving fromFurry Sketch!