月間1600万PVを誇るECサイトの裏側を聞く!クラシコム×カヤック合同勉強会

こんにちわ、こんばんわ、おはようございます、谷脇です。

今回は、北欧、暮らしの道具店を運営している株式会社クラシコムさんとカヤックで、合同勉強会を行いました。この記事では、その模様をお伝えします。

クラシコムさんの社内勉強会「ヒュッゲ」

クラシコムさんのオフィスにカヤックのメンバーがお邪魔して、勉強会を行いました。勉強会をした部屋はこのような感じです。

f:id:mackee_w:20191004182419j:plain

クラシコムさんでは月1回程度、「ヒュッゲ」と呼ばれる勉強会を開催しているそうです。「ヒュッゲ」はデンマーク語で「居心地の良さ」という意味です。名前の通り、会場は居心地よく、温かい雰囲気の中で勉強会は行われました。

f:id:mackee_w:20191004182413j:plain

それでは、各発表を簡単に振り返っていきます。

まずは自己紹介

まず、クラシコムさんの技術スタックや社員のみなさんが、1枚のスライドで自己紹介。

f:id:mackee_w:20191007175310j:plain

ふむふむ、Laravelを中心としたサービス構成なんですね。もともとECのSaaSを使っていたところを、数年前から自社開発のものに切り替えた歴史があるそうです。詳細はこちらの記事に載っています。

エンジニア3人で作った月間1600万PVのECサイト「北欧、暮らしの道具店」を支えるシステムの裏側

その他にも、クラシコムのみなさんの経歴や趣味のことなどで盛り上がりました。

また、写真で分かる通り、序盤からすでに、ビールとピザと寿司がデプロイされているカジュアルな会でした。

弊社庄司の「自己紹介LT」

カヤックからは庄司が、今までカヤックでやってきた仕事を交えての自己紹介LTを行いました。

f:id:mackee_w:20191007175211j:plain

私も知らない、2000年代前半から今に至るカヤックでの仕事の変遷が、つらつらと述べられました。クラシコムさんのお仕事に関連するような、ECサイトの受託開発の話題で盛り上がりました。

庄司の「どうやって作るかわからないから、他のECのサイトのURLやフォームのパラメータを全部見て回って『こうやって作るのか』となったのが面白かった」というのが印象的でした。

「OSSや社内ツールの名付けで考えたこと」

続いて私から、ソフトウェアの名付けについての発表をさせていただきました。

f:id:mackee_w:20191004193314j:plain

ソフトウェアのコンポーネントに、何らかの名付けをする行為は必ず発生します。どのような基準で命名がされているか疑問に思ったので、私が作ってきたOSSや社内システムの例を挙げながら、パターンに分類してみました。

「3ヶ月振り返りの壁打ちをしてわかったこと」

クラシコムの佐々木さんの発表です。

f:id:mackee_w:20191007175240j:plain

2人のジュニアクラスのエンジニアとの1on1を通して、どのように成長を促していくか、という話でした。

1on1でメンティーがKeep/Problem/Tryを挙げていく中で、ProblemからどうTryにつなげるかを悩んでいるときに、メンターのエンジニアは答えをすぐ言ってしまうことがあるそうです。それでもぐっと飲み込んで、メンティーが自分で答えを出せるような質問を投げかけていく、という話が印象に残りました。佐々木さんも「どうしてもパッと答えを言ってしまうことがある」というように、私も同じような状況で「あっ、答え言っちゃった」となることが度々あります。

また、当初は、別々の時間に1on1をやっていたそうですが、2人で一緒に振り返りをまずしてから1on1に臨むようになり、1on1で話されることの精度があがったというエピソードも興味深かったです。

「AWSの『隙間』を埋める隙間家具OSSの開発」

この勉強会の前日に行われた、AWS DevDayでの藤原の発表を、駆け足で話しました。

f:id:mackee_w:20191007175300j:plain

AWS DevDayでの発表スライドやレポートなどはこちらを参照してください。

スライド

【セッションレポート】AWSの「隙間」を埋める隙間家具OSS開発【#AWSDevDay】 - DevelopersIO

AWSのフルマネージドサービスとうまく付き合うためのコツについての発表。具体的には、AWSのサービスを組み合わせて使う場合に生じるサービス間の隙間を、あとから取り外せる疎結合のソフトウェアを作る事例の紹介がありました。

カヤックもクラシコムさんもAWSを使っているので、双方からあるあるという声や、そういう思想で作られていたのかという反響もありました。

「『フィットする暮らし』を支える技術」

マイブームがフォントのサブセット化という、クラシコム廣瀬さんの発表です。「北欧、暮らしの道具店」のビジネス面のミッションと、過去や今の技術構成を説明しながら、ミッションを遂行するのに必要な技術的な変化を提案した発表でした。

f:id:mackee_w:20191007175319j:plain

最近はブログメディアであったりWebドラマであったりと、ECサイトの枠を超えたサービスを提供しているクラシコムさん。新しいことをやるのに、現在の複数のサービスによって分かれるインフラ構成では運用が難しく、開発スピードが出ないという問題提起から話は始まりました。

そこで、歴史的経緯で複数のサービスに分かれた構成から、出来るだけ運用がしやすいようにまとめていく構成に直していくというもの。

昨今隆盛しているマイクロサービシーズのように細かく分けていくのと違い、集約していく提案でした。しかし、流行っているやり方をそのまま当てはめるのではなく、取り組んでいる課題やチームの形態に応じた適切なインフラ構成を考えていくべきという、クラシコムさんの意志を感じました。

まとめ

クローズドな合同勉強会だからか、サービスの中身や、具体的な手法にまで言及した深い議論ができ、双方にとって大変有意義な時間になりました。また、二次会の居酒屋では、弊社の藤原を中心にインフラ相談会のような形になりました。

f:id:mackee_w:20191004182348j:plain

カヤックでは、こんな勉強会いいなぁと思ってくれる仲間や、合同勉強会を一緒に開いてくださる会社さんを募集しています。興味がありましたら、私のTwitterアカウントにメンションやDMを飛ばしていただくか、お知り合いのカヤック社員にご連絡ください。

(アーティストさんへ)LDRなブルームの注意点、そしてHDRとLDRについて

f:id:hirasho0:20191003165340p:plain

こんにちは。技術部平山です。

以前LDR(Low Dynamic Range)なブルームエフェクトについて書きましたが、 今回はLDRでブルームをやる時に起こる問題点について、アーティストさん向けに書いてみます。

結論から言うと、「後から足すのはそう簡単じゃない」という事になります。 実際、最近とある製品で「入れたい」という話になったのですが、 保留という結論になってしまいました。

LDRで実装したものには結構な制約があり、 「後からチョロっと入れておしまい」にはしにくい事情があるのです。

0から255しかない

ゲームでは毎フレーム全画面の絵を描き直すわけですが、 その時に書き込むキャンバスには、大きく分けて二種類あります。

  • LDR(Low Dynamic Range。ローダイナミックレンジ)
  • HDR(High Dynamic Range。ハイダイナミックレンジ)

LDRと言えば普通、0から1の範囲の数字を、256段階で書き込みます。 1画素の容量はRGBとアルファそれぞれに1バイトで、4バイトです。

大抵HDRと言う時には、0から65000の範囲の数字を、65000段階で書き込みます。 数字が小さい所では段階が細かくなるように工夫されており、 0から1の間はだいたい2000段階くらいになります。 LDRでは256段階しかないですから、8倍細かいわけです。 その上、10とか100とか1000といった大きな値も書き込めるので、 LDRとは表現力が全く違ってきます。 そのかわり、1画素の容量は倍の8バイトです。

ダイナミックレンジというのは「表現の幅」のことでして、 LDRでは0から1しかないものが、HDRでは0から65000まで広がるわけですから、 HDRの方がいいに決まっているわけです。

しかし、残念ながら、容量が大きいものは遅いのです。 また、古い機械ではそもそもHDRが使えません。 とはいえ、本来、ブルームエフェクトはHDRなキャンバスが前提の技術です。 それをLDRでやるのは基本的に無理をしている、ということを、 知っていただきたいと思います。

では、その無理の詳細に踏み込んでいきましょう。

キャラの光沢をまぶしくしたい

とりあえず冒頭の画面を見てください。 アレなキャラの頭がギラリと光っていますね。 ブルームエフェクトによって、ハイライトがポリゴン境界をはみ出して光っています。 アニメ的な表現を想定していて、背景はQuadにテクスチャをベタ貼りして 照明計算はしていません。 しかし、この絵を作るには若干の手間をかける必要があるのです。

まず、何も考えずにやってみましょう。 背景とキャラを普通に配置します。

f:id:hirasho0:20191003165400p:plain

キャラはメタリックなマテリアルにして、ハイライト以外は暗めにしておきました。

さあ、ブルームを有効化しましょう。

f:id:hirasho0:20191003165348p:plain

白飛びしすぎですね。 入れた設定は、

  • RGBそれぞれが0以上のところを
  • 1倍の強度でぼかして足す

というものです。 黒い所はほとんど広がりませんが、白い所は白が広がり、 赤い所は赤が広がるので、まあこうなります。 すごく明るい所だけを広げたいのであって、 大して明るくない所は広げなくて良いのですから、 これは設定が悪いですね。 では設定を変えてみましょう。

f:id:hirasho0:20191003165350p:plain

マシにはなりましたが、背景は光らなくていいですよね。 この設定は、

  • RGBそれぞれが0.5以上のところだけを取り出してぼかす

というものですが、0.5以上という条件だと 背景がこんなに光ってしまいます。光るのはキャラの頭だけでいいのです。 もっと数字を上げてみましょう。

f:id:hirasho0:20191003165354p:plain

0.9以上の所だけを取り出すことにしましたが、やっぱり背景光ってますね。

まあ当然のことで、背景の画像を見ていただければわかるように、 真っ赤な所や、すごく緑な所があるわけです。 真っ赤な所はRが1くらいあるわけで、 0.9なんて余裕で超えてしまいます。

え、どうすればいいの?ということになるわけです。

HDRならこんな問題は起こらない

問題は「赤かったり緑だったりする所」、つまり背景と、 「すごく光ってる所」、つまりキャラのハイライトの区別がつかないことです。 白は1でして、太陽がガッツリ反射してすごく明るい所も同じく1です。 後者だけを取り出す、ということはそもそもできません。

でも、もしキャンバスがHDRであれば、こんな問題はありません。 65000まで書けるからです。キャラのハイライトは100とか1000とかを書き込み、 背景はたかだか1くらいまでしか書き込まない、 ということになれば、区別は容易につきます。 すごく明るい所だけ取り出してぼかすのは簡単です。

問題は、「1までしか入らない」ということにあるのです。 LDRでブルームをやるのが無茶、ということの意味がおわかりかと思います。

ではどうするか?

手はいくつかあるのですが、一番既存処理に影響を与えないでやれる手は、 「LDRなキャンバスに1より大きいものが入るようにする」です。

え、と思うかもしれません。「LDRなキャンバスは0から1しか入らない」 ってさっき言いましたからね。

しかし、解釈を変える、という手があります。 「1が入っていたらそれは10のことだ」と後で解釈しなおせばいいのです。 つまり、最初に描画する時に1/10の値を書き込みます。 背景の白は1を1/10にして0.1を書き込み、キャラのハイライトは10を1/10にして1 を書き込みます。

そうすれば、「0.1より大きい所だけ取り出してぼかす」ということができます。 そして全部処理が終わってから、結果を10倍すればいいのです。

「そんなことができるならそうすればいいじゃん」と思われるかもしれません。 しかし、これには犠牲が伴います。 まあやってみましょう。

10分の1で描いて、終わってから10倍

まず、背景のテクスチャの色を1/10します。 テクスチャをいじるのは面倒なので、マテリアルカラーを乗算して1/10にしましょう。

f:id:hirasho0:20191003165337p:plain

キャラの方はライトの強度を1/10にします。

f:id:hirasho0:20191003165334p:plain

環境光(アンビエント)も1/10にする必要があることに注意してください。 Unityの場合LightingSettingsで環境光の強度を下げます。

f:id:hirasho0:20191003165329p:plain

さて、この結果、

f:id:hirasho0:20191003165357p:plain

ブルームなしでこういう絵になります。ほぼ真っ暗ですが、 キャラのハイライトだけは白く残っていますね。期待が持てます。 実は照明計算を行うシェーダでは、計算結果は10とか100とかになっており、 1以上にならなかったのはキャンバスがLDRだからです。 ライトの強さを1/10にしても、100が10になるだけで、まだ十分明るいので、 こうして明るい色が描き込まれることになります。

では、この状態で、0.1以上を取り出してぼかす設定にしてブルームを有効化してみましょう。 私のブルームにはカラーフィルタ機能がついていまして、 処理が終わった後に何倍かすることができるので、それを使います。

f:id:hirasho0:20191003165332p:plain

ColorScaleに10を入れてあり、これで10倍になります。 ブルームの強度はほどよく調整して(この例では4くらい)みました。

f:id:hirasho0:20191003165344p:plain

確かにハイライトだけが光ってはいて、背景はそのままなんですが、 この四角いガタガタしたのは何なんでしょうか。

これが先程言った「犠牲」です。犠牲にしたのは、「精度」です。

元々LDRの場合、0から1を256段階で表していました。 1/10して描き込む場合、本来の0から1の範囲は段階が10分の1になってしまい、 たった25段階になってしまいます。ハイライト以外の所も色が段々になっていて 汚ないのがおわかりでしょうか。たった25段階しかない状態にしたものを、 後から10倍すれば、汚ないのは当然です。

妥協

自然界の物の明るさの幅というのはすごいものがあって、 そのあたりの物と太陽の明るさの比は10倍や100倍どころの話ではなく、 万とかの桁になります。 普通に見えているものと、光っている電球でも100倍くらいは違いがあり、 本当は10とか100とかが入っている所だけをぼかしたいのですが、 精度のせいで10倍すらままなりません。

仕方ないので、2倍で我慢しましょう。 明るさを1/2にして描画し、後で2倍して戻します。 先程0.1を入れた所を0.5にし、 10を入れた所は2にします。

f:id:hirasho0:20191003165340p:plain

実は、これが冒頭のスクリーンショットです。

0から1に128段階しか使えないので結構精度は落ちており、 マッハバンドも出てしまっていますが、 LDRで無理矢理やるなら我慢するしかないでしょう。 もっと凝った手もあるにはありますが、負荷が重くなるので 意味がなくなってしまいます。

まとめ

今回紹介したのは、LDRでブルームをやる一番安い方法だと思います。 「何分の1かの明るさで暗く書いて、いらない所が光らないような値を設定してブルームし、明るさを元に戻す」 という手順です。現実的には精度の問題があって2倍が限度でしょう。

さて、安いとは言え、後付けで導入するとなると問題は簡単ではありません。 最低限、テクスチャをいじらないで描画する明るさを変えられる必要があります。 テクスチャを直すコストは到底許容できません。 標準のUnlit/Textureシェーダは乗算色を指定できないので、これで作っていると シェーダの差し替えから必要になってしまいます。

また、乗算色を指定できるシェーダを使っていてテクスチャを直さずに済むとしても、 今回の例のように「照明計算なし(Unlit)」なものがあると、マテリアルの個別設定が必要になります。 その意味で、アニメ的な背景や、加算で乗せるエフェクトなどは厄介です。 エフェクトについては別カメラに分けて「エフェクトを描画する前にポスプロを済ませる」 という手もありますが、背景はそうも行きません。 まあ背景はそんなに数はないでしょうけれども、やっぱり手間は手間ですよね。

ところで、ここまでLDRでがんばっておいて何ですが、 「HDRにしちゃう」という選択肢は当然あります。 ブルームをやるならそれが一番素直な選択肢です。 高級なメモリを積んでいて、キャンバス(レンダーテクスチャ)の容量が増えても あまり遅くならない機械であれば、それでもいいはずです。 機械の性能を何らかの手段で判定して、 HDRに切り換える手はあるかと思います。 カメラをHDRを使うように設定して、 標準のPostProcessingStackを使えばいいでしょう。 性能が余っているなら妙な工夫は不要です。

ただ、「HDRの時はアンチエイリアスが効かない」といった制限がある機械も 過去にはありました。ある程度の数の機械で試して、 性能や機能制限を見ておくのが無難かと思います。