雪月風花
里山の一日を春夏秋冬の流れで表現したCG作品です。

クリックして再生
日の出のシーンです。朝霧が漂う山の間から太陽が昇ります。大気散乱はRedshiftのPhysical Sky(PRG Clear Sky)を利用しています。レンズフレアを有効にして日の出の印象を強めています。 霧や雲はSkyboxで作成しvdbで保存した上でRedshiftのVolumeマテリアルを適用してレンダリングしています。
Scene01「日の出」
太陽の光で棚田が照らされ、雪が溶けていきます。雪溶けは時間とともに雪マテリアルのディスプレイスメントマップの高さを下げていくことで表現しています。エッジのギザギザが出てしまっていたので、 ポリゴンの分割等の対処が課題です。
Scene02「雪溶け」
こちらのカットはレンダリングが間に合わなかったので一枚絵です。春煙の中、桜の花びらが風に舞うシーンです。AfterEffectsで桜吹雪と朝霧を動かしています。 木のブラッシュアップに時間が取れなかったので、木のクオリティが低めなのが心残りです。
Scene03「春煙」
入道雲と青い空が写り、夏草の陽炎を表現しました。こちらも小屋のディテールアップができておらず、浮いた形になってしまったのが課題でした。
Scene04「夏陽炎」
日が暮れはじめて風になびく黄金の稲穂を表現しました。 草の風揺れは固定パターンの揺れ方の草を数種類用意してばらけさせて表現しました。風の強さを表現するような細かなパーティクルを入れたかったです。
Scene05「秋茜空」
日が沈み雪が降り始めるシーンです。雪はAfterEffectsで降らせています。雪の積もらせ方は「雪解け」のアプローチの逆を行っています。
Scene06「初雪」
夜中、すっかり雪に埋もれた棚田、雪が小降りになり月が見えはじめるシーンです。 雲を動かしつつ、雪のマテリアル部分のエッジのエミッションを強めて、暗いライティングでも形態感が出るようにしました。 小屋の明かりを印象付けるようにもしています。
Scene07「冬月」
コンセプト
里山の一日を春夏秋冬で表現しました。朝が春、昼か夏、夕方が秋、夜が冬のシーンとしました。 写真のスライドショーとは違って、CGで作る意義を出すために移り変わりの様子をできるだけ表現するようにしました。
重視したキーワード:「空」「太陽」「雲」「朝霧」「山」「棚田の地形」「稲」「小屋」「桜の木」「風」「陽炎」「雪」「月」
使用ツール・スケジュール
使用ツール
Houdiniメインで制作しました。プロシージャルモデリングやプロシージャル配置に慣れることや、 USD+Solarisの環境に慣れる目的もあります。 今回Redshift(GPUレンダラー)を使用しました。レンダリングが比較的高速なのと、機能が充実していました。 ただ、高速ではあるものの、全カット(50秒/30FPS/540p)のレンダリングは30時間くらいかかっています。
| モデリング | Houdini |
| テクスチャリング | Substance Designer |
| レイアウト | Houdini(Solaris) |
| レンダリング | RedShift for Houdini |
| レンダリング自動化 | Hydra |
| コンポジット(フォグの合成) | Substance Designer |
| コンポジット(特殊効果) | AfterEffects |
制作期間
6/17~9/10の約3か月間です。平日は1日30分程度、休日は1日平均4時間程度の作業時間、合計制作時間としては120時間程だと思います。
| 期間 | 内容 |
|---|---|
| 06/17 - 06/23 | HoudiniのラーニングやSolaris+Redshiftの技術調査 |
| 06/24 - 06/30 | AfterEffectでのムービーテンプレート作成、USDでのレンダリングシーン構築 |
| 07/01 - 07/07 | フォトバッシュでのイメージ作成 |
| 07/08 - 07/14 | 1つ目のカット作成 |
| 07/15 - 07/28 | 2つ目のカット作成 |
| 07/29 - 08/10 | 山と棚田と木の作成 |
| 08/11 - 08/25 | 7つ分のカット作成、うち4つは止め絵状態 |
| 08/26 - 09/10 | 雲アニメーション、草揺れのアニメーション、雪のアニメーション、レンダリング、AfterEffectでの合成 |
制作過程
まず、1カットでのアセット作成、配置、ライティング、レンダリング、画像出力、フレーム遷移、コンポジットのシーケンスをつなげる事からスタートしました。 初めて使用するツールが多かったので、Solarisでマテリアル作成、Houdiniビューポートでのテクスチャ表示、Redsiftでのビューポートレンダリングなどを確認しました。 カットを1つ作成しつつ、全体の流れをイメージできるようにフォトバッシュで作成しつなげて動画を作成しました。 こちらはHoudini上で大量の草を揺らす実験です。各ポイントのデータの持ち方や処理負荷のイメージができるようにしました。 マテリアルを修正して稲の形状を整えて改めてレンダリングしたのがこちらです。 背景に山を配置しました。木が配置されていないと不自然なので、ここにどう大量の木を植えるかがポイントです。 ビルボードの抜きの部分はRedshiftのマテリアルノードを設定する際に、OpacityではなくSpriteでシェーダ設定をするのがカギでした。 Spriteだと不透明で扱えるため、重なった部分の破綻もなく処理も軽いといいことづくめです。 あと、山の木の3割は枯れ木と言われています。ビルボードの配置に枯れ木を3割含めるようにするとより山らしさが出てきます。
フォグの計算はExponentialFogの計算を参考にしました。 デプスだけではなく霧や雲の影響を考慮するためにAoVでボリュームも出力し、ボリュームの輝度をもとにフォグで使うデプス値を動かしてかかり方のムラを出すようにしました。 フックスクリプトにstageという変数でUSDの情報が渡ってきます。 書き換えるのがattributeかprimかrelationshipかで呼び出す関数は変わりますので、USDの関数仕様を確認しつつスクリプトを書きます。
草を揺らす
HeightFieldベースの棚田
アセットに関しては、まず舞台の中心となるHeightFieldベースで棚田を作成を行いました。雑にマテリアルを割り当ててみたのがこちらです。 テクスチャのノーマルが悪目立ちしているのでリピートの調整が必要でした。 ビルボード木の作成
山の広範囲の面積にそのままポリゴンで作成した木を配置するにはあまりにGPUに負荷がかかるのので、処理が軽いビルボードの木を制作します。 ビルボードテクスチャの作成もHoudiniで行います。 ビルボード木の配置
こちらがビルボード木を配置したものです。上から見ると違和感はありませんが、横から見た時の稜線の木の重なり方が不自然に見えてしまいます。 Substance Designer を使ったポスト処理
フォグの合成はSubstanceDesignerで行いました。sbsrenderを使うことでレンダリングの後段処理に自動で適用するフローを構築できるためです。 ただ、SubstanceDesginerはテクスチャ解像度が2の累乗である必要があるので、流し込む前にImageMagickのextentでサイズを広げて加工後cropする という方法をとりました。sbsrenderへの画像のパスの受け渡しは--set-entryオプションで渡せます。 Substanceに定数を渡す必要がある場合はImageMagickでその値の1x1単色画像を生成することで渡すようにしました。 SubstanceDesigner内のフォグ合成処理はPixelProcessorを使用しました。フォグの計算はExponentialFogの計算を参考にしました。 デプスだけではなく霧や雲の影響を考慮するためにAoVでボリュームも出力し、ボリュームの輝度をもとにフォグで使うデプス値を動かしてかかり方のムラを出すようにしました。
PixelProcessorの処理
フォグ合成前
フォグ合成後
Hydraを使ったバッチ処理
シーンの構築をusdファイルとして出力すると、huskコマンドでスクリプト制御でレンダリングが可能です。 スクリプトで一括で全フレームレンダリングできる、所謂バッチレンダリングの環境が構築できます。 また、huskでレンダリングする際、スクリプト制御で色々な設定を変えられるので、柔軟性が高いです。 例えば空だけレンダリングするような設定にスクリプトから書き換える場合は下記のようなPythonスクリプトをhuskコマンドのpre-render script引数に渡すことで、 USDのstage階層を書き換えた状態でレンダリングができます。 # only MainColor
products = stage.GetRelationshipAtPath('/Render/rendersettings.products')
products.SetTargets(['/Render/Products/RenderProductColor'])
# hide Geometry node
geometry_visible = stage.GetAttributeAtPath('/Geometry.visibility')
geometry_visible.Set('invisible')
# disable flare
flare_settings = stage.GetAttributeAtPath('/cameras/camera1.redshift:camera:RS_campro_flareEnable')
flare_settings.Set(False)
# hide sun
sun_scale = stage.GetAttributeAtPath('/lights/rsPhysicalSky1/rssunsky.redshift:light:PhysicalSky_sun_disk_scale')
sun_scale.Set(0.0)
products = stage.GetRelationshipAtPath('/Render/rendersettings.products')
products.SetTargets(['/Render/Products/RenderProductColor'])
# hide Geometry node
geometry_visible = stage.GetAttributeAtPath('/Geometry.visibility')
geometry_visible.Set('invisible')
# disable flare
flare_settings = stage.GetAttributeAtPath('/cameras/camera1.redshift:camera:RS_campro_flareEnable')
flare_settings.Set(False)
# hide sun
sun_scale = stage.GetAttributeAtPath('/lights/rsPhysicalSky1/rssunsky.redshift:light:PhysicalSky_sun_disk_scale')
sun_scale.Set(0.0)