Xcode 9 の Scene Editor、iOS 11 の Scene File の Procedual Sky のバグについて
Xcode 10 を触っていて気づいたのだが、Xcode 9 の Scene Editor、iOS 11 の Scene File では Procedual Sky で正しい表示がされないバグがある。
ちなみに Scene Editor での Procedual Sky の適応方法は、何らかのノードを選択後、Scene Inspector (Command + Option + 7) を押して、Background や Environment で Procedual Sky を選択する。
問題点
問題点が2点ある
- Xcode 9 の Scene Editor では Adjustments のパラメーターが適応されない
- Xcode 9 の作成する Scene File の Adjustments のパラメーターが保存されるが、実行時適応されない
Xcode の Scene Editor 自体、SceneKit で作成されているため、Scene Editor で出ているバグはビルドした実際のアプリでも同様のバグが発生する。
ちなみに、Adjustments のパラメーターはトーンマップ用のパラメーター。
原因
Scene Editor で設定する Procedual Sky は Model I/O の MDLSkyCubeTexture を使用しており、MDLTexture のサブクラスとなっている。
テクスチャとして空をキューブマップとして描画するのだが、中身は MTLTexture なのでパラメーターを与えただけではテクスチャ内容の変更ができない模様。
update() 関数があり、これが呼ばれるとテクスチャの再生成し MDLSkyCubeTexture として生成するのだと思われる。
このような流れで MDLSkyCubeTexture を使用するのだが、
どうやら Scene Editor や SceneKit では update() 関数が呼ばれていない可能性がある。
MDLSkyCubeTexture について
6面のキューブマップテクスチャが生成され、背景画像が作成される。
キューブマップの背景に関しては過去記事を参照。
内部的には幅 64、高さ 384 の画像のテクスチャとなっている模様。
(もしかしたら Mipmap で1番小さい画像を取得している可能性あり)
パラメーター
Scene Editor で設定できるのものが全てのパラメーターとなっている
シミュレーションパラメーター
パラメーター名 | 型 | 説明 |
---|---|---|
turbidity | Float | 空のかすみや曇り具合 |
sunElevation | Float | 太陽の位置 |
upperAtmosphereScattering | Float | 空の色に影響を与える値 |
groundAlbedo | Float | 空の透明度に影響を与える値 |
groundColor | CGColor? | 擬似的な地面の色 |
horizonElevation | Float | 地面の色をレンダリングする際に下の中心を基準にした角度 (単位はラジアン) |
トーンマップパラメーター
パラメーター名 | 型 | 説明 |
---|---|---|
gamma | Float | 適用するガンマ補正値 |
exposure | Float | 適用する露出補正値 |
brightness | Float | 明るさを強調させるための値 |
contrast | Float | コントラストを強調させるための値 |
saturation | Float | 彩度を強調させるための値 |
highDynamicRangeCompression | vector_float2 | テクスチャの色の輝度の圧縮曲線を決める2つのパラメータ(Photoshop のトーンカーブのようなもの) |
Xcode 10 のシーンエディターの値を使い、Xcode 9 で MDLSkyCubeTexture を表示してみる
以下、Xcode 10 でのパラメーター。
Unity のデフォルトのような背景になる。
パラメーター名 | 値 |
---|---|
turbidity | 1.0 |
sunElevation | 0.778 |
upperAtmosphereScattering | 0.4 |
groundAlbedo | 0.33 |
groundColor | #383838 (0.22,0.22,0.22,1.0) |
horizonElevation | 0 |
gamma | 0.05 |
saturation | -2 |
コード
コードで書いてみる。
SCNScene の background に設定するため、SCNScene の初期化の後に以下を書く。
// MDLSkyCubeTexture の初期化 let skyTexture = MDLSkyCubeTexture( name: "sky", channelEncoding: .uInt8, textureDimensions: vector_int2(1024, 1024), turbidity: 1.0, sunElevation: 0.778, sunAzimuth: 0, upperAtmosphereScattering: 0.4, groundAlbedo: 0.33 ) let groundColor = UIColor(red: 0.22, green: 0.22, blue: 0.22, alpha: 1.0) skyTexture.groundColor = groundColor.cgColor skyTexture.gamma = 0.05 skyTexture.exposure = 0 skyTexture.brightness = 0 skyTexture.contrast = 0 skyTexture.saturation = -2 skyTexture.update() scene.background.contents = skyTexture scene.lightingEnvironment.contents = skyTexture
MDLSkyCubeTexture の初期化には名前と channelEncoding、textureDimensions の値がある。
channelEncoding はピクセルフォーマット。
SceneKit での Metal は bgra8Unorm なので uInt8 を設定している。
textureDimensions はキューブマップ各1面の大きさ。
基本的には正方形を指定する形になると思われる。
表示結果
このような感じになる。
update() 関数を呼ばないとこんな感じ。