Apple Engine

Apple, iPhone, iOS, その周辺のことについて

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 を選択する。

f:id:x67x6fx74x6f:20180703194346p:plain

 

問題点

問題点が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面のキューブマップテクスチャが生成され、背景画像が作成される。
キューブマップの背景に関しては過去記事を参照。

appleengine.hatenablog.com

 

内部的には幅 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面の大きさ。
基本的には正方形を指定する形になると思われる。

 

表示結果

このような感じになる。

f:id:x67x6fx74x6f:20180703194758p:plain

 

update() 関数を呼ばないとこんな感じ。

f:id:x67x6fx74x6f:20180703194838p:plain