LoginSignup
0
0

More than 1 year has passed since last update.

swifty-creatives (Swiftライブラリ解説) その1

Last updated at Posted at 2023-02-28

swifty-creatives

  • Swift製のクリエイティブコーディングフレームワーク
  • SwiftUIのViewやUIViewなどとして簡単にアプリに導入することができる
  • 3D描画やアニメーションなど、一通りのことはできる
  • Processingライクな書き方ができる
  • https://github.com/yukiny0811/swifty-creatives

続き

基本的な描画方法

Sketch1.swift
import SwiftyCreatives

//スケッチプログラムを作ります
class Sketch1: Sketch {
    override func draw(encoder: SCEncoder) {
        color(1, 1, 1, 1) //RGBAで色を指定
        box(3, 3, 3) //Boxを幅3・高さ3・奥行き3の大きさで描画
    }
}

//SwiftUIのViewとしてこのように記述します
struct ContentView: View {
    var body: some View {
        ZStack {
            SketchView(Sketch1())
        }
        .background(.black) //背景は黒が映える
    }
}

ForQiita 2023年-02月-28日 23.06.14.gif

このように白いBoxが表示されました。デフォルトでカメラ操作がONになっているので、自由に視点を移動することができます。今回はMacOSで実行していますが、iOSやMacCatalystでも同様に動作します。

現時点(v1.11.2)で対応している図形一覧
Box
Rectangle
Triangle
Circle
Line
3D Model (objのみ)
Img (画像)
Text
UIViewObject (UIViewのxibをそのまま3D空間に配置できます。ボタンもタップ可能。)

Push/Popを用いた描画

Sketch2.swift
class Sketch2: Sketch {
    let count = 20
    override func draw(encoder: SCEncoder) {
        for i in 0..<count {
            color(1, Float(i) / 20, 0, 1) //色を設定
            pushMatrix()
            rotateY(Float.pi * 2 / Float(count) * Float(i)) //座標系をY軸を中心に回転させる
            translate(10, 0, 0) //現在の座標系でx軸方向に10移動する
            box(1, 1, 1) //サイズ1の立方体を描画する
            popMatrix()
        }
    }
}

このようにリング状にBoxを配置することができました。

画像の描画

Sketch3.swift
class Sketch3: Sketch {
    // 画像を読み込みます
    let image = Img().load(
        image: NSImage(named: "image")!.cgImage(
            forProposedRect: nil,
            context: nil,
            hints: nil
        )!
    ).multiplyScale(12) //サイズを縦横比を保ったまま12倍します
    override func draw(encoder: SCEncoder) {
        image.draw(encoder) //描画します(encoderは気にしなくて大丈夫です)
    }
}

ForQiita 2023年-02月-28日 23.26.27.gif
このように画像も3D空間上に配置することができました。

ホバーしたら色が変わる長方形

Sketch4.swift
class Sketch4: Sketch {
    let rect = HitTestableRect().setColor(f4(1, 1, 1, 1)).setScale(f3(5, 5, 5))
    override func draw(encoder: SCEncoder) {
        rect.drawWithCache(encoder: encoder, customMatrix: getCustomMatrix()) //当たり判定を含んで描画する場合にはdraw()ではなくdrawWithCache()を用います
    }
    override func mouseMoved(with event: NSEvent, camera: some MainCameraBase, viewFrame: CGRect) {
        let mousePos = mousePos(event: event, viewFrame: viewFrame) //マウスの座標を取得する関数が用意されています
        let ray = camera.screenToWorldDirection(
            screenPos: mousePos,
            width: Float(viewFrame.width),
            height: Float(viewFrame.height)) //カメラから飛ばすrayを作成します
        //rayを使ってrectの当たり判定計算を行います
        //もし当たっていたらそのワールド座標を、当たっていなかったらnilが帰ってきます
        if let hitPos = rect.hitTestGetPos(origin: ray.origin, direction: ray.direction) {
            rect.setColor(f4(0, 1, 0, 1)) //緑色に
        } else {
            rect.setColor(f4(1, 1, 1, 1)) //白色に
        }
    }
}

ForQiita 2023年-02月-28日 23.33.33.gif
このようにマウスがホバーすると色が変わるようになりました。当たり判定はRect・UIViewObject・Box・Imgにつけることができます。

クリックすると回転する長方形

Sketch5.swift
class RotatingRect: HitTestableRect {
    @SCAnimatable var rotation: Float = 0.0 //SCAnimatableラッパーをつけると簡単にアニメーションができます
}

class Sketch5: Sketch {
    let rect = RotatingRect().setColor(f4(1, 1, 1, 1)).setScale(f3(5, 5, 5))

    //update()は毎フレームdraw()の前に呼ばれます
    override func update(camera: some MainCameraBase) {

        //$rotation.update()を呼ぶことによりアニメーションする値を更新しています
        //deltaTimeはその名の通り前回のフレームからの時間です。固定値でもいいですが、deltaTimeを用いるとマシンスペックによる挙動の差が少なく抑えられます
        rect.$rotation.update(multiplier: deltaTime * 5) 
    }
    override func draw(encoder: SCEncoder) {

        //$rotation.animationValueに現在のアニメーション用の値が入っているので、それを用いてY軸回転させます
        rotateY(rect.$rotation.animationValue)

        //getCustomMatrix()はとりあえずつけておいてください
        rect.drawWithCache(encoder: encoder, customMatrix: getCustomMatrix())
    }
    override func mouseDown(with event: NSEvent, camera: some MainCameraBase, viewFrame: CGRect) {
        let mousePos = mousePos(event: event, viewFrame: viewFrame)
        let ray = camera.screenToWorldDirection(
            screenPos: mousePos,
            width: Float(viewFrame.width),
            height: Float(viewFrame.height))
        if let _ = rect.hitTestGetPos(origin: ray.origin, direction: ray.direction) {
            rect.rotation += Float.pi
        }
    }
}

ForQiita 2023年-02月-28日 23.43.36.gif
このように簡単にease-outでアニメーションすることができました。

その他

長くなってしまうので別記事でまた続きを解説します。

まだ紹介していない機能
テキストの描画
TextFactory
自作クラスでSketchの関数を使う方法(SCPacket)
PostProcessingと自作シェーダーの読み込み
PostProcessingプリセット(角丸やBloom)
3Dモデル
Cameraのコンフィグ(透視投影・平行投影など)
描画のコンフィグ(フレームレートなど)
ブレンドモード
UIViewObjectとxibとIBAction
Lighting
Fog

swifty-creativesで作れるものの例

3Dグラフ L-System
Boxいろいろ Bloomエフェクト
ExampleMacOSApp 2023年-03月-01日 0.06.07.gif CheckMacOS 2023年-03月-01日 6.46.57.gif

|

関連

https://qiita.com/yukiny/items/43ff5ded25ecbe6caf22
https://qiita.com/yukiny/items/7b5692b503fc7db921d4
https://github.com/yukiny0811/swifty-creatives

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0