【Swift】SpriteKitの使い方。SKEffectNodeで画像にフィルタをかける(Swift 3.0、XCode 8.0)
SKEffectNodeの続き
前回の記事でSKEffectNode(以下、エフェクトノード)を使って、画像をぼかす方法とフィルタの種類について説明した。⇒「記事」
本記事はその続きで、画像の色を変更するフィルタの変化を確認する。
以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる方はご利用下さい。⇒「テスト用プロジェクト」
なお、本記事からXCodeはVer8.0、SwiftはVer3.0を使って検証を行う。事前準備では、鳥と2匹の猿をシーンに配置しておいた。エフェクトノードを使って片方の猿に効果を与えて比較する。
CIColorClamp
描画色の範囲(最小値、最大値)を赤、緑、青、アルファで指定するフィルタ。
猿を赤っぽくしてみよう。TestScene.swiftを以下のコードに変更する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
// // TestScene.swift // import Foundation import SpriteKit class TestScene:SKScene { //現在シーン設定時の呼び出しメソッド override func didMove(to view: SKView) { //シーンに配置するノードを作成する。 let background = SKSpriteNode(imageNamed: "field") let monkey1 = SKSpriteNode(imageNamed: "monkey") let monkey2 = SKSpriteNode(imageNamed: "monkey") let bird = SKSpriteNode(imageNamed: "bird_brown") //ノードの座標を指定する。 background.position = CGPoint(x: self.frame.midX, y: self.frame.midY) monkey1.position = CGPoint(x: self.frame.width*1/3, y: self.frame.height/2) monkey2.position = CGPoint(x: self.frame.width*2/3, y: self.frame.height/2) bird.position = CGPoint(x: self.frame.width*2/3, y: self.frame.height*4/5) //ノードをシーンに配置する。 self.addChild(background) self.addChild(monkey1) self.addChild(bird) //エフェクトノードを作成する。 let effect = SKEffectNode() //エフェクトノードの位置を設定する。 effect.position = CGPoint(x: 0, y: 0) //フィルタを作成する。 let filter = CIFilter(name:"CIColorClamp") filter!.setValue(CIVector(x: 0.1, y: 0.1, z: 0.1, w: 0), forKey: "inputMinComponents") filter!.setValue(CIVector(x: 0.9, y: 0.1, z: 0.1, w: 1.0), forKey: "inputMaxComponents") //フィルタを設定する。 effect.filter = filter //エフェクトノードの子に猿を追加する。 effect.addChild(monkey2) //エフェクトノードをシーンんに配置する。 self.addChild(effect) } } |
CIVectorのXは赤色、Yは緑色、Zは青色、Wはアルファを表している。例えば、黄色っぽく半透明にしたい場合は以下のコードのようにする。
1 2 3 4 5 |
//フィルタを作成する。 let filter = CIFilter(name:"CIColorClamp") filter!.setValue(CIVector(x: 0.1, y: 0.1, z: 0.1, w: 0), forKey: "inputMinComponents") filter!.setValue(CIVector(x: 0.9, y: 0.9, z: 0.1, w: 0.5), forKey: "inputMaxComponents") |
CIColorControls
彩度、明るさ、コントラストの値を調整するフィルタ。
1 2 3 4 5 6 7 |
//フィルタを作成する。 let filter = CIFilter(name:"CIColorControls") filter!.setValue(2.0, forKey: "inputSaturation") //彩度(デフォルト1) filter!.setValue(0.5, forKey: "inputBrightness") //明るさ(デフォルト0) filter!.setValue(2.0, forKey: "inputContrast") //コントラスト(デフォルト1) |
CIColorMatrix
赤、緑、青、アルファごとに用意されたベクターを元の画像に加えて、特定の色を強くしたり、弱くしたりする。
以下のコードはデフォルトの設定値なので画像の色は変化しない。
1 2 3 4 5 6 7 8 9 |
//フィルタを作成する。 let filter = CIFilter(name:"CIColorMatrix") filter!.setValue(CIVector(x: 1.0, y: 0.0, z: 0.0, w: 0), forKey: "inputRVector") //赤ベクトル filter!.setValue(CIVector(x: 0.0, y: 1.0, z: 0.0, w: 0.0), forKey: "inputGVector") //緑ベクトル filter!.setValue(CIVector(x: 0.0, y: 0.0, z: 1.0, w: 0.0), forKey: "inputBVector") //青ベクトル filter!.setValue(CIVector(x: 0.0, y: 0.0, z: 0.0, w: 1.0), forKey: "inputAVector") //アルファベクトル filter!.setValue(CIVector(x: 0.0, y: 0.0, z: 0.0, w: 0), forKey: "inputBiasVector") //バイアスベクトル |
赤ベクトルのxを0にするとどうなるか。
1 2 |
filter!.setValue(CIVector(x: 0.0, y: 0.0, z: 0.0, w: 0.0), forKey: "inputRVector") //赤ベクトル |
赤っぽさが無くなって緑っぽい画像になった。ちなみに、黄色はRGB(赤緑青)のRとGを使って表現される。黄色に近い猿の顔から赤色が無くなることで、緑色の顔になった。
逆に赤ベクトルのxを2倍にするとどうなるか。
1 2 |
filter!.setValue(CIVector(x: 2.0, y: 0.0, z: 0.0, w: 0.0), forKey: "inputRVector") //赤ベクトル |
赤が強くなってオレンジモンキーになった。
CIColorPolynomial
三次多項式で色が変更されるらしい。何かややこしい話になってきたぞ。
以下のコードはデフォルトの設定値なので画像の色は変化しない。
1 2 3 4 5 6 7 8 |
//フィルタを作成する。 let filter = CIFilter(name:"CIColorPolynomial") filter!.setValue(CIVector(x: 0.0, y: 1.0, z: 0.0, w: 0.0), forKey: "inputRedCoefficients") //赤係数 filter!.setValue(CIVector(x: 0.0, y: 1.0, z: 0.0, w: 0.0), forKey: "inputGreenCoefficients") //緑係数 filter!.setValue(CIVector(x: 0.0, y: 1.0, z: 0.0, w: 0.0), forKey: "inputBlueCoefficients") //青係数 filter!.setValue(CIVector(x: 0.0, y: 1.0, z: 0.0, w: 0.0), forKey: "inputAlphaCoefficients") //アルファ係数 |
公式リファレンスの例と同じ値を設定してみよう。
1 2 3 4 5 6 7 8 |
//フィルタを作成する。 let filter = CIFilter(name:"CIColorPolynomial") filter!.setValue(CIVector(x: 0.0, y: 0.0, z: 0.0, w: 0.4), forKey: "inputRedCoefficients") //赤係数 filter!.setValue(CIVector(x: 0.0, y: 0.0, z: 0.5, w: 0.8), forKey: "inputGreenCoefficients") //緑係数 filter!.setValue(CIVector(x: 0.0, y: 0.0, z: 0.5, w: 1.0), forKey: "inputBlueCoefficients") //青係数 filter!.setValue(CIVector(x: 0.0, y: 1.0, z: 1.0, w: 1.0), forKey: "inputAlphaCoefficients") //アルファ係数 |
CIExposureAdjust
露出値(EV値)を設定するフィルタ。露出とは、簡単にいうと光を当てて感光させることをいう。EV値を高くして暗いシーンを明るくしたり、逆にEV値を低くして明るすぎるシーンを暗くしたりするのに使われる。
露光値をデフォルトの2倍にしてみよう。
1 2 3 4 |
//フィルタを作成する。 let filter = CIFilter(name:"CIExposureAdjust") filter!.setValue(1.0, forKey: "inputEV") //露出値(デフォルトは0.5) |
実行結果。まぶしいくらいに光が当たっているように見える。
CIGammaAdjust
中間調の強さを設定するフィルタ。中間調とは、明るい色と暗い色の中間の明るさのことをいう。
中間調の強さをデフォルトの倍にしてみよう。
1 2 3 4 |
//フィルタを作成する。 let filter = CIFilter(name:"CIGammaAdjust") filter!.setValue(1.5, forKey: "inputPower") //(デフォルトは0.75) |
暗い感じになった。
CIHueAdjust
全体的に色合いを変更するフィルタ。
1 2 3 4 |
//フィルタを作成する。 let filter = CIFilter(name:"CIHueAdjust") filter!.setValue(3.0, forKey: "inputAngle") |
設定値を増加させていくと色合いはループする。以下の動画は設定値を0.1ずつ増加させながらフィルタを設定した実行結果
CILinearToSRGBToneCurve
ガンマカーブからsRGB色空間に向かった変換で色の強さを変換するフィルタ。
1 2 3 |
//フィルタを作成する。 let filter = CIFilter(name:"CILinearToSRGBToneCurve") |
黒い部分を除いて、全体的に色が明るくなった。
CISRGBToneCurveToLinear
上のフィルタとは逆に、sRGB色空間からガンマカーブに向かった変換で色の強さを変換するフィルタ。
1 2 3 |
//フィルタを作成する。 let filter = CIFilter(name:"CISRGBToneCurveToLinear") |
全体的に色が暗くなった。CILinearToSRGBToneCurveとは逆の効果だ。
CITemperatureAndTint
色温度と色合いを設定するフィルタ。色温度とは、暖かい色(オレンジ系)、冷たい色(青色系)などを表すための尺度のことで、単位はケルビン(K)で表される。
デフォルトは昼光色の6500Kである。ちなみに、電球色(暖色)は3000K。
1 2 3 4 5 6 |
//フィルタを作成する。 let testFilter = CIFilter(name:"CITemperatureAndTint") testFilter!.setValue(CIVector(x: 6500.0, y: 0.0), forKey: "inputNeutral") testFilter!.setValue(CIVector(x: 6500.0, y: 0.0), forKey: "inputTargetNeutral") |
ピンとこないので、inputTargetNeutralのXを0から1フレームごとに50づつ加算してみた。
以下が実際のプレイ動画。3000Kでオレンジ色になり、そして徐々に青白い色に変化していった。
以下の動画は、inputTargetNeutralのYを0から1フレームごとに5ずつ加算した実行結果。徐々に黄緑色になり最後は急に真っ黒になった。
CIToneCurve
トーンカーブを使って色合いやカラーを調整するためのフィルタ。
以下のコードはデフォルトの設定。
1 2 3 4 5 6 7 8 |
//フィルタを作成する。 let testFilter = CIFilter(name:"CIToneCurve") testFilter!.setValue(CIVector(x: 0.0, y: 0.0), forKey: "inputPoint0") testFilter!.setValue(CIVector(x: 0.25, y: 0.25), forKey: "inputPoint1") testFilter!.setValue(CIVector(x: 0.5, y: 0.5), forKey: "inputPoint2") testFilter!.setValue(CIVector(x: 0.75, y: 0.75), forKey: "inputPoint3") testFilter!.setValue(CIVector(x: 1.0, y: 1.0), forKey: "inputPoint4") |
トーンカーブとは、補正前(X軸)と補正後(Y軸)の照度レベルの違いをグラフで表したもので、補正前後で何も変わらない場合は、下図のように右斜め45度のグラフで表される。
補正前が0.3なら補正後も0.3、補正前が0.7なら補正後も0.7、つまり何も変わらないということだ。
トーンカーブを下図のようにしたらどうなるか。補正前が0なら補正後は1.0、補正前が0.7なら補正後は0.3。。つまり、色が逆転することになる。
実際にやってみよう。フィルタを以下のコードに変更する。
1 2 3 4 5 6 7 8 |
//フィルタを作成する。 let testFilter = CIFilter(name:"CIToneCurve") testFilter!.setValue(CIVector(x: 0.0, y: 1.0), forKey: "inputPoint0") testFilter!.setValue(CIVector(x: 0.25, y: 0.75), forKey: "inputPoint1") testFilter!.setValue(CIVector(x: 0.5, y: 0.5), forKey: "inputPoint2") testFilter!.setValue(CIVector(x: 0.75, y: 0.25), forKey: "inputPoint3") testFilter!.setValue(CIVector(x: 1.0, y: 0.0), forKey: "inputPoint4") |
以下は実行結果。色が反転した。
CIVibrance
肌のトーンを維持しながら、画像の彩度を調整するフィルタ。
1 2 3 4 |
//フィルタを作成する。 let testFilter = CIFilter(name:"CIVibrance") testFilter!.setValue(1.0, forKey: "inputAmount") |
CIWhitePointAdjust
基準白色点を変更するフィルタ。以下は赤を設定したコード。
1 2 3 4 |
//フィルタを作成する。 let testFilter = CIFilter(name:"CIWhitePointAdjust") testFilter!.setValue(CIColor.red(), forKey: "inputColor") |