kugi's notebook

やったこと、思ったことなどつらつらと書きます

蛍光現象のレンダリング

はじめに

こちらの記事は レイトレ合宿8アドベントカレンダー8週目の記事です。

今回は蛍光現象とそのレンダリング手法について書きたいと思います。

蛍光現象

みなさんは蛍光現象をご存知でしょうか? 遊園地の入場チェックで手にスタンプをされたことのある方やブラックライトで照らすことで浮かび上がるアートなどを見たことがある方もいらっしゃるかもしれません。

蛍光現象とは、蛍光分子がある特定の波長の光を吸収して、その吸収したエネルギーによって別の波長の光を放出する現象のことです。

例えばこちらのTRICKマーカーの水性インクにも蛍光分子が含まれています。

先日購入したTRICKマーカー

それぞれのインクの蛍光分子が、UV LEDの光(紫外線)を吸収して、赤、緑、青と異なる波長の光を放ちます。

室内照明環境下だと見えないが、
ブラックライトを照射すると文字が浮かび上がってくる

蛍光分子にはこのように、吸収する光の波長領域を表す励起スペクトル(Excitaion Spectrum)と放出する光の波長領域を表す蛍光スペクトル(Emission Spectrum)を持ちます。

点線:励起スペクトル、実線:蛍光スペクトル

グラフは蛍光顕微鏡などで用いられる蛍光色素であるAlexa Fluor®抗体の蛍光特性です。

蛍光スペクトルビューアーを使うと選択した蛍光色素の励起スペクトル、蛍光スペクトルを確認でき、励起光を指定して蛍光現象のシミュレーションをグラフ上で行うことができるのでおすすめです。

蛍光現象のさらに詳しい説明は下記を参照してください。

蛍光の基本原理 | Thermo Fisher Scientific - JP

その他の蛍光の例

実は蛍光現象は身近なところにも応用されています。 紫外線を吸収して青白い光を発光させてより服の白さを目立たせるため、洗剤などに使われているようです。

花王 | 製品Q&A | 【成分・働き】蛍光増白剤とは?

また、医学の分野では蛍光色素で細胞を染色して観察する蛍光顕微鏡なども使われています。

蛍光現象と蓄光の違い

蛍光現象と似たものとして、蓄光があります。

フォトルミネセンス(Photoluminescence)という括りでは、蓄光も光を吸収し、そのエネルギーによって光を再放出する過程です。 蓄光の場合は発光の寿命が長く、物質への光照射をやめてからも発光し続けます。

詳しい違いとしては光を吸収した蛍光分子の励起状態が異なるようです。

ヤブロンスキー図
Wikipedia より引用

蛍光 - Wikipedia

ちょうど先日立ち寄った100円ショップに蓄光材質のものが売っていたので買ってみました。

蓄光材質
室内照明で照らしている状態から、照明を消すと発光する

冒頭のTRICKマーカーによる蛍光の場合は暗所でUV LEDライトを用いて照らしていましたが、今回の場合は何も照らしていない状態で発光し続けています。

また、iPhoneのLEDライトで照らした場合とUV LEDライトで照らした場合で比較してみたところUV LEDの方が明るく発光しました。 購入した蓄光素材の詳細な励起特性についてはわかりませんが、より短波長領域の光を吸収するようでした。

蛍光現象の2つの特性

蛍光現象には以下の2つの特性があります。

  • 出射スペクトルと蛍光スペクトルの関係
  • トークスの法則

出射スペクトルと蛍光スペクトルの関係

出射スペクトルは蛍光として放出される光の各波長での強度を表したものです。

また、蛍光分子が蛍光特性として持つ蛍光スペクトルは励起スペクトルにおけるピークでの波長を励起光(吸収する光)とした時の出射スペクトルです。下図の場合、励起光1がピークでの励起光になります。

蛍光スペクトルと出射スペクトル

図のように、異なる波長の励起光が蛍光分子に与えられたとしても、放出される出射スペクトルは蛍光スペクトルの相似形になるという特性があります。

トークスの法則

トークスの法則

トークスの法則は蛍光として放出される光のエネルギーは、吸収されるエネルギーよりも低く、励起光の波長より長波長領域の光になるという法則です。

図の蛍光分子の場合、紫外線(UV LEDライトの光)を吸収して、可視光領域の光が放出されます。UV LEDライトで照らしてヒトの目によって観測できるようになるのはこのためです。

蛍光現象のレンダリング

さて、前置きが長くなってしまいましたが、 ここからは蛍光現象のレンダリング手法について紹介します。

スペクトラルレンダリング

特性からもわかるように、蛍光現象は光の波長に依存した光学現象です。波長依存性の高い光学現象をレンダリングするためには、一般的なRGBレンダリングではなく、波長ごとの値を考慮したスペクトラルレンダリングが必要です。

スペクトラルレンダリングとRGBレンダリング

RGBレンダリングではあらかじめ現実の光のスペクトルを等色関数を用いてRGBに変換し、そのRGBを用いて照明計算を行います。 それに対し、スペクトラルレンダリングでは光のスペクトルからサンプリングされた値を用いて照明計算を行った結果をRGBに変換するため、物理的に正しい光のシミュレーションを行うことができます。

スペクトラルレンダリングについては、shockerさんのページやPenguinさんのレイトレアドベントカレンダー2021の記事がとても参考になります。

スペクトラルレンダリング - Computer Graphics - memoRANDOM

スペクトルレンダリング - Qiita

多重重点的サンプリングを用いた手法

Yamamotoらの手法では、蛍光現象の2つの特性に基づいて、スペクトル強度 I_i(\lambda)の励起光に対する蛍光のスペクトル強度I_o(\lambda)を以下のようにモデル化しています。

  •  I_i(\lambda): 励起光のスペクトル強度
  •  I_o(\lambda): 蛍光のスペクトル強度
  •  E(\lambda): 励起スペクトル
  •  F(\lambda): 蛍光スペクトル
  •  K: 励起に関する係数
  •  \eta: 蛍光の強度を表す係数(  \eta = 2.0 \times 10^{-2} と設定)
 \displaystyle
I_o(\lambda) = KF(\lambda)
 \displaystyle
K = \eta \int_\Lambda E(\lambda)I_i(\lambda) d\lambda

 K における積分モンテカルロ積分を用いて、以下のように計算します。

  •  p(\lambda_j): 波長 \lambda_j がサンプリングされる確率
 \displaystyle
K = \eta \frac{1}{N}\sum_{j = 1}^{N} \frac{E(\lambda_j)I_i(\lambda_j)}{p(\lambda_j)} \Delta \lambda

また、波長をサンプリングする際、光源と蛍光分子の特性に基づいて波長を確率的にサンプリングしています。

  •  p_F(\lambda): 蛍光分子の蛍光スペクトルを考慮したPDF(確率密度関数)
  •  k_{F_t}: 各波長における蛍光スペクトルの値の総和
  •  w_{F_t}: 蛍光分子を含有した物体の面積とを k_{F_t}考慮した重み
 \displaystyle
p_F(\lambda) = \sum_{i = 1}^{N_\lambda} w_{F_t} \frac{F_i(\lambda)}{k_{F_i}}
 \displaystyle
k_{F_t} = \int_{\Lambda} F_i(\lambda) d\lambda

光源のスペクトルを考慮したPDF  p_L(\lambda)についても p_F(\lambda)同様に計算します。

そして最終的に、蛍光スペクトルに対する重み w_Fと光源に対する重み w_Lで重み付けしたPDF  p_{FL}(\lambda)を用いて波長を多重重点的サンプリング(Multiple Importance Sampling)します。

 \displaystyle
p_FL(\lambda) = w_F p_F(\lambda) + w_L p_L(\lambda)

Spectral Rendering of Fluorescence using Importance Samplingより引用

レンダリングの際にはPPPM(Probablistic Progressive Photon Mapping)を用いてレンダリングパス毎にフォトン、レイに割り当てる波長をサンプリングしています。

BBRRDFを用いた手法

Alisaらは蛍光と非蛍光の反射を表現するために、物質中に含まれる蛍光分子の含有率を考慮したBBRRDF(Bispectral Bidirectional Reflection and Reradiation Distribution Function)をモデル化しています。

BRDF(双方向反射率分布関数)に対して、BispectralReradiation が追加されているように、位置と方向に加えて、入射時(吸収される光)の波長と出射時(蛍光として放出される光)の波長に依存した関数です。

  •  a(\lambda): 励起スペクトル
  •  e(\lambda): 蛍光スペクトル
  •  r(\lambda): 反射率スペクトル(非蛍光成分)
  •  Q: 蛍光分子の吸収するエネルギーに対して放出するエネルギーの比率
  •  \delta_{\lambda_i, \lambda_o}: 非蛍光成分において入射波長 \lambda_iと出射波長 \lambda_oを切り替えるデルタ関数
  •  f_{fluor}: 蛍光BBRRDF
  •  f_{nonfluor}: 非蛍光BBRDF
 \displaystyle
f_{fluor}(\lambda_i, \omega_i, \omega_o, \lambda_o) = \frac{c a(\lambda_i) Q e(\lambda_o)}{\pi}
 \displaystyle
f_{nonfluor}(\lambda, \omega_i, \omega_o) = \frac{(1 -c) a(\lambda) r(\lambda)}{\pi}

これらを合わせて、BBRRDFは以下のように表現されます。

 \displaystyle
f_r(\lambda_i, \omega_i, \omega_o, \lambda_o) = \frac{\delta_{\lambda_i, \lambda_o} (1 -c a(\lambda_i)) r(\lambda_i) + c a(\lambda_i) Q e(\lambda_o)}{\pi}

 \omega_i,  \omega_oを引数に持つように、入射と出射の方向の観点では相互作用を起こしそうですが、蛍光現象おいてはストークスの法則があるため、一般的に放出された蛍光による相互作用(二次蛍光)は起こりません。

 c, Q, a(\lambda), r(\lambda) [0, 1]の値をとり、 c = 0の場合は非蛍光の完全拡散反射BRDFになります。

波長のサンプリングとしては、以下の2ステップで行っています。

  1. 蛍光現象が発生するかをサンプリングする
  2. 新しい波長をサンプリングする

まず蛍光現象が発生するかについては、光源パスで発生する確率 P_lとカメラパスで発生する確率 P_cによって決定します。

 \displaystyle
P_l = \frac{c a(\lambda_i) Q}{c a(\lambda_i) Q + (1 - c a(\lambda_i))r(\lambda_i)}
 \displaystyle
P_c = \frac{c \int_\Lambda a(\lambda) d\lambda Q e(\lambda_o)}{c \int_\Lambda a(\lambda) d\lambda Q e(\lambda_o)+ (1 - c a(\lambda_o))r(\lambda_o)}

これらの確率は光源パス、カメラパスで反射された(蛍光現象によるエネルギーも含む)エネルギーに対する、蛍光として反射されたエネルギーの割合です。

 P_l の場合は光源から照らされて吸収される入射波長 \lambda_i P_c の場合は蛍光現象によって放出される出射波長 \lambda_oが与えられます。また、 P_lの分母の第1項の蛍光スペクトルの積分 \int_\Lambda e(\lambda) d\lambda = 1 として省略されています。

蛍光現象が発生したと決定した場合は、使用した確率に応じて波長をサンプリングする際に用いるPDFが変わります。

  • 光源パス( P_l): 蛍光スペクトル e(\lambda)をPDFとする
  • カメラパス( P_c): 励起スペクトル a(\lambda)をPDFとする

光源パスの場合は、光源 => 光の吸収 => 励起状態 => 光の放出 => カメラ

また、カメラパスの場合はその逆順の過程を経ることに注意が必要です。

A Simple Diffuse Fluorescent BBRRDF Modelより引用

左図は蛍光物質の球がUVライトによって照らされたシーンです。

右図において、横軸は左端を0、右端を1として吸収したエネルギーに対して放出したエネルギーの比率 Qを表し、縦軸は上段から c = 0, 0.2, 0.4, 0.6, 0.8, 1を表しています。

まとめ

今回は蛍光現象とそのレンダリング手法について紹介しました。 暗闇で仄かに輝く蛍光や燐光かっこいいですよね!

冒頭で紹介した蛍光スペクトラルビューアーは蛍光色素のスペクトルデータを出力したり、グラフを画像として書き出すことも可能です。 ポチポチしているだけでも割と楽しいので気になった方は是非遊んでみてください!

本来は蛍光物質のボリュームレンダリングについても紹介したかったのですが、間に合いそうになかったので今回はここまでにしたいと思います...。

それでは!

参考文献

ISUCON12予選 振り返り

はじめに

7月23日(土)に開催されたISUCON12 予選に参加してきました!

今回はその振り返り記事になります。

0次予選

1回目は気づいたら埋まっており、 2回目はなんとかGitHub連携、Discord連携まで行けたものの、 チーム名を決めておらず、一瞬手が止まってしまい敗退。 そして3回目は寝過ごしてしまい、3回あった予選の参加申し込みは全敗...

追加募集枠で滑り込み、なんとか0次予選は突破しました...。

事前準備

私は今年で2回目の参加で、社会人としては初参戦でした。 メンバーは会社の同期のkoikoiくんとmtsgiくんを誘いました。

ふたりともISUCONは初参加だったので、私が参加したISUCON10での記憶や過去問、資料などを共有して、matsuuさんの公開されているISUCON11予選のAMIを用いて練習会を開きました。

github.com

my.cnfを用意してMySQLのslow query logを吐き出す方法などを学びました。

[mysqld]
slow_query_log = 1
# ログファイルに吐き出す設定
slow_query_log_file = /var/log/mysql/slow.log
# # テーブル(mysql.slow_log)に吐き出す設定
log_output = FILE
long_query_time = 0.1
log_queries_not_using_indexes = 1

本番でも使用したmy.cnf

予選当日の様子

使用言語は3人とも使ったことのあるPythonを選びました。

事前に一度3人で練習していたので、午前中のうちに環境構築を終え、 お昼を食べて本格的にログの解析や改善できる部分を探しに行きました。

mtsgiくんがdeploy.shを用意してくれてめちゃくちゃ助かりました!

情報の共有

練習会ではNotionを使って情報共有をしていたため、 競技中も気付きメモを用意して、解析結果などを共有しました。

気付きメモ

行った改善

解析結果をもとに、koikoiくんとmtsgiくんはindexを追加できそうなところがないかを調べ、 私はキャッシュできそうなところがないかを見ていきました。

visit_historyにindexが追加できそうだったので以下を追加してくれました。

alter table visit_history add index tenant_competition_created_at_idx (tenant_id,competition_id,created_at);

データのキャッシュについては、絶大な効果があったわけではありませんが、 個々のtenant DBへ接続してデータを取得するconnect_to_tenant_db()が各APIの処理内で呼ばれていたので、 初期データについてはあらかじめキャッシュし、テナント追加毎にリストにもデータを追加するように修正しました。 (5c74983)

まとめ

結果としては最終スコア 2000 点で、初期状態のGO実装のスコアを超えることができませんでした...。 ただ、小さな改善や予選会までの練習でログの解析についても学ぶことができたので次回に活かしていきたいです。

最終スコア

スコア推移

やりたかったこととして、

  • 一意IDの割り振りテーブルの改善
  • サーバーの分散(DBとアプリケーション)
  • nginxのログ活用

などたくさんありますが、同期と一緒に良い経験を積むことができました。 来年もこのチームで参加して、さらに高得点を目指したいと思います!

モーションブラーのレンダリング

はじめに

こちらの記事はレイトレーシング Advent Calendar 2021の18日目の記事です。

(大遅刻をしてしまいました...)

qiita.com

こちらのアドカレに投稿させて頂くのは初めてになります。

昨年までは広島で蛍光現象のレンダリングについて研究をしていて、 現在は東京でゲームプログラマをしています。

最近はレイトレを改めて一から勉強するため、1週間レイトレをベースに進めています。

github.com

RAY (Notionに残しているメモ)

今回は Ray Tracing: The Next Week から「モーションブラー」についての記事になります。

モーションブラー

モーションブラーは撮影のタイミングで被写体やカメラが移動することによって起きます。 シャッタースピードが速いカメラで動いている被写体を撮影すると、被写体が止まっているような写真を撮ることができます。

実験してみた

以下のように、左から右へ移動する赤甲羅を被写体にし、カメラのシャッタースピードを変えて撮影します。

iPhoneのカメラでは設定からシャッタースピードを変えることができないみたいなので、 「Mカメラ」というアプリを使って変更しました。

M=Camera

M=Camera

  • KANAME OHARA
  • Photo & Video
  • Free
apps.apple.com

シャッタースピード 1/15秒

シャッタースピード 1/500秒

変更したのはシャッタースピードのみなので、露光時間が短い 1/500 秒の方では少し暗めの画像になっていますが、赤甲羅のブレは少なく、くっきりとした輪郭が撮影できています。

逆に露光時間の長い、シャッタースピード 1/15 秒の方では、モーションブラーがつき、赤甲羅が横に走って行ったということ画像からがわかります。

モーションブラーのレンダリング

それでは、モーションブラーありの画像をレンダリングしていきます。

モーションブラーはシャッタースピードを変えることで表現することができます。 そのため、カメラとカメラから飛ばすレイに時間の概念を導入します。

このカメラではシャッターが t_0 から t_1 の間開いていることになり、シャッタースピードt_1 - t_0 秒です。

get_ray()関数は時刻 $t$ においてカメラから飛ばしたレイを取得する関数です。 (ここで時刻 t[t_0, t_1])

// カメラ
class camera {
  public:
    /// ...

    float _t0 {0.0f};
    float _t1 {1.0f};

    /// ...

    ray get_ray(float u, float v) {
        float time = _t0 + drand48() * (_t1 - _t0); // 時刻 t は t_0から t_1の間
        return ray(origin, lower_left_corner + u * horizontal + v * vertical - origin, time); // 時刻 t に飛ばしたレイを返す
    }
}

class ray {
 public:
  ray(const vec3& origin, const vec3& direction, float time = 0.0f) {
    _origin = origin;
    _direction = direction;
    _time = time;
  }
  vec3 origin() const { return _origin; }
  vec3 direction() const { return _direction; }
  float time() const { return  _time; }
  vec3 point_at_parameter(float t) const { return _origin + t * _direction; }

  vec3 _origin; // レイの原点
  vec3 _direction;  // レイの進む方向
  float _time; // 時間
};

そして、描画するオブジェクトに対しても時間の概念を持たせます。

Ray Tracing: The Next Weekではt_0からt_1の間でp_0からp_1に移動する球を実装します。

/// 移動球
class moving_sphere : public hitable {
 public:
  moving_sphere() {}
  moving_sphere(vec3 cen0, vec3 cen1,
                float t0, float t1,
                float r,
                material *m) :
                center0(cen0), center1(cen1),
                time0(t0), time1(t1),
                radius(r),
                mat_ptr(m) {};
  virtual bool hit(const ray &r, float tmin, float tmax, hit_record &rec) const;
  vec3 center(float time) const; // 時刻 t における球の中心位置
  vec3 center0, center1;
  float time0, time1;
  float radius; // 球の半径
  material *mat_ptr; // 球のマテリアル
};

/// time0 から time1の間で移動する球の
/// 時刻 t における中心座標
vec3 moving_sphere::center(float time) const {
  return center0 + ((time - time0) / (time1 - time0)) * (center1 - center0);
}

そして、レイと球の交差判定、散乱、反射を計算する際にはある時刻 t におけるレイの計算として処理を拡張します。 時刻tにおけるレイを用いて計算をすることで、時刻t_0から時刻t_1の間にカメラのセンサーが受け取った像の平均値としてシミュレーションすることができます。

描画結果

モーションブラーなし

モーションブラーあり

モーションブラーありの方では、時刻t_0から時刻t_1の間、左から右に移動する球を用いました。

まとめ

今回はじめてレイトレーシングアドベントカレンダーに参加させていただきました。 (にもかかわらず遅刻してしまい申し訳ないです...)

本当は研究もしていた蛍光現象の記事を書きたかったのですが、 準備が間に合いませんでした...。

来年こそはしっかり準備をして、蛍光現象についてのアドカレ記事を書きたいです。

頑張るぞ〜〜〜!

引用

https://raytracing.github.io/books/RayTracingTheNextWeek.html

週末レイトレーシング 第二週 (翻訳)

レッツクライム💪

はじめに

こちらの記事はUnityゲーム開発者ギルド Advent Calendar 2021の11日目の記事です。

adventar.org

今年もUnityゲーム開発者ギルドの皆さんには大変お世話になりました。 来年もどうぞよろしくお願いいたします!

今回はUnityの話...ではなく、 クライミングの話をします。

ライミングはいいぞ

さて、みなさん登っていますか? 私は最近週2ペースで登りに行っています。

今回は以下の流れでクライミングについてご紹介したいと思います。

「クライミング」って?

東京オリンピックでも競技種目になりましたが、 「クライミング」よりも「ボルダリング」という言葉を耳にすることの方が多いかもしれません。

実はライミング(ロッククライミング)は登ることの総称で、 ボルダリングはその一部です。

ロープを使わず、落ちても致命的なケガにならない通常3〜5m程度の高さの壁を登ります。

(CLIMBING-NETより引用)

ライミングの中にはロープを使って登る「リードクライミング」などもあります。

ロープをカラビナに引っ掛けていきながら登ります

私はボルダリングだけでなく、リードも好きなので言葉としては「クライミング」をよく使います。

ボルダリングの基本的なルール

今回はクライミングの中でも、ボルダリングの基本的なルールについてまずは説明します。

日本にもボルダリングジムはたくさんあるので、1度は登りに行ったことがあるという方もいらっしゃるかもしれません。

ボルダリングウォール

ボルダリングでは、クライミングシューズ以外はロープや手袋といった補助器具を使用せずに、ホールド(壁に取り付けられた突起物)や壁そのものを使って登っていきます。

しかし、ただ上に登れば良いというわけではありません。 登る際は、スタートホールドからゴールホールドまで決まったコース(課題)を登っていきます。

青ホールドの課題

画像のコースだと、青いホールドだけを使って登っていく課題になります。

また、スタートとゴールは静止した状態でないといけません。 (例えば、ゴールホールドにタッチするだけではゴールにならない。)

基本的な制約は以上で、コースのホールド使う手順や登り方自体は自由です。 もちろん壁に足を置いてバランスを取っても問題ありません。 (実はこれがとても重要)

コースの表記方法はジムごとによっても違い、ホールドの色で分けられていたり、テープで分類されていたりします。 また、コースごとに難易度(グレード)が「6級、5級、...、1級、初段、2段、...」と決まっていて、自分のレベルにあったコースを登ったり、難しめのコースに挑戦したりいろんな楽しみ方があります。

なんだかゲームみたいで楽しそう!!

ちょっとしたコツ

さて基本的なルールもお伝えしたので登る際のコツについて少しだけお話ししたいと思います。

実は握力はそこまで必要ない

握力が重要と思われがちですが、実はそこまで握力が強くなくても登れます。 (私自身も両手50kg前後)

ホールドにはペットボトルキャップよりも小さいものから、両手で抱え切れない大きさのものまであります。 「掌全体で握り潰す力」というより、「適切な持ち方を維持する力」の方が重要だと言えるかもしれません。

また、先ほどもありましたが、バランスや体感も非常に重要です。 腕で登るのではなく、体全体を使って登ると楽に登ることができます。

以下のことを意識して登ってみてください!

  • 腕をできる限り伸ばす
  • そのためには腰を低く落とす
  • 足を置く位置に意識して登る

登っていない時間も大切

ボルダリングジムに行くと壁をジッと見つめる人や、壁をみながら手を動かしている人がたくさんいます。

ライミングは登っていない時間も非常に重要です。 コースを見て、登る際のシミュレーションをすることを「オブザベーション」と言います。

実際に登ってみるとわかるのですが、オブザベーションをせずに登ると次のホールドの位置やコースが全体的にどう進んでいくのかが全く分からず、 身動きが取れなくなってしまいます。また、安全マットの外からコースをみていた時の視点と壁に取り付いている状態での視点は全く違うので尚更わからなくなります。

スタートとゴールの位置を確認することはもちろんですが、途中のホールドの位置や足場の位置、ホールドの持ち方についても入念に確認した上で登りましょう! (という私もオブザベ不足でキョロキョロしながら登ってしまうことは多々あります...)

実際に登る前に、一度頭の中で登るべし!

日本代表クライマーの方々の動画もオススメです。

www.youtube.com

だからやめられないクライミング

私は中学3年の冬にクライミングに出会いました。 登らなくなってしまった時期もありましたが、 登り始めて以来、引っ越す先々で登ってきました。

私が思う「クライミングのここがいい!」というポイントについてもご紹介したいと思います。

自分の成長がわかる

ルールの部分でも説明しましたが、登るコースには難易度があります。 自分の目標となる難易度を目指して登ることでレベルが上がっていくことを実感することができます。

また仮に登れない壁(コース)にぶつかったとしても、 なぜ登れなかったのか考えて繰り返し挑戦することで、いつかは(きっと!)登ることができます。

「壁を通して自分自身と向き合い、成長を感じれる」のでとても好きです。

登れなかったときの悔しさをバネに壁と向き合おう!

行きつけのジム

ここまで読んできたみなさんはきっと

「早く登りにいきたい!」

と思っているはず!!

最後に私の行きつけのジムを紹介したいと思います。

TOKYO STONE SESSION

THE STONE SESSION TOKYO (@tsstokyo) • Instagram photos and videos

スカイツリーの近くにあるジムで、スカイツリーを見ながら登ることができます。 課題のグレードが隠されているのが特徴的です。(スタッフの方に聞けば教えてくれます!)

B-PUMP TOKYO 秋葉原

pump-climbing.com

4階建てで曲面壁やアウトドア壁もあります。 ショップの品揃えも豊富なのでシューズを購入する際はおすすめです!

Piglet

piglet-climb.com

最近はここで同期と退勤クライムしています。 とてもアットホームなジム!

まとめ

今回は趣味のクライミングについて書かせていただきました。 実は最近ギルドの方とも登りに行くようになり、クライミング好きが増えて嬉しいです。

「登ってみたい!」という方は是非お声掛けください。 一緒に登りに行きましょう〜!

unity1week「2」振り返り ~「Kani と Uni」に込めた想い~

はじめに

お久しぶりです。kugiです。 4月から社会人になり、慌ただしくも楽しい日々をおくっています。

さて、今回はゴールデンウィークで参加した Unity1週間ゲームジャム - お題「2」 の振り返りをしたいと思います。

f:id:kugi_masa:20210530114106p:plain

u1wの概要についてはコチラ

参加に踏み切るまで

実は今回のu1wはギリギリまで参加するかを悩んでいました。 というのも、

  • 社会人になった今、1週間のモチベーションと気力を保ったまま開発できるのか...
  • あらためて1人でゲームが作れるか不安...

といった気持ちがモヤモヤっと出てきたのです。

前回、前々回とチーム参戦だったので、今の力量でチャレンジするという意味でも、参加するならソロ開発にしようと思っていました。

前回の 「お題『回』」 でnattuhanさん、つっちーさんの3人で作成した NOA's Projectは学生として参加する最後のu1wで、自分の中では一つの区切りと捉えていました。

学生の頃はイベント駆動開発がほとんどで、ゆっくりインプットするということを次第にしなくなっていました。ちょうど社会人なり、時間もあるゴールデンウィークなので積読している技術書を読んだり、ゆったりStayHomeでハンティングライフに没頭するのもありだな〜と考えていました。

しかし、Twitterやギルド(Unityゲーム開発者ギルド)で参加している方達の進捗やワイワイ感を見たら自分は絶対 「参加すれば良かった...」と思うこともわかっていました。

私はu1wをゲームを1週間でつくる(今回は遅刻しましたが...)イベントというだけでなく、お祭りのようなものだと捉えています。

最近では200、300を超えるゲームが1週間で投稿されます。それの制作過程が進捗としてTwitterなどで共有される。そして1週間後に実際に遊べる。また、ぱふもどきさんまっともぉんさんをはじめとするいろんな方が実況プレイしてくださる。そしてそして、u1wが終わった後も青木ととさんが主催されているu1w共有会で制作の過程や開発者の方の目標などを聞くことができる。

もちろんゲームを投稿せずに遊ぶ側にまわったり、実況や共有会を視聴するだけでも十分楽しめるお祭りだと思います。

それにプラスして、自分もゲームを投稿した場合、自分のゲームを遊んでもらえてレビューを貰えることもある。もしかしたら、今回自分のゲームを遊んでくれた方が、次回参加するときのチームメンバーになることだってあるかもしれません。

これはもう、参加するしかないでしょ...!!!

と気づいたらお祭りに参加したい欲がモヤモヤを上回っていました。

目標を決めよう

モヤモヤを上回っていました」と書いたものの、モヤモヤが消え去ったわけではありません。 モチベーション維持一人で作りきるために、まずは今回の目標を設定することにしました。

今回設定した目標は以下の2つになります。

  • オンラインゲームに挑戦する
  • kugiにしか作れないゲームを作る

一つ目の目標としてオンラインゲームを選んだのは、これまでに挑戦したことのないことだったからです。 これまでのu1wを振り返ってみても、何かしらやったことのないことに触れてみるようにしていました。

お題 作ったゲーム 挑戦したこと
さがす あにまるハンター ・就活で作成した企画書をベースにゲームを作ってみる
・u1wに初挑戦
密蜂〜Cluster Bee〜 ・自作モデルを使用して作る
・LightmapをベイクしたりLightingを調整してみる
・u1w共有会で発表
ふえる Groundwater ・URPでPost-processing、Shadergraph使ってみる
・Timelineでアニメーション
あける すきすきスキマん ・u1wでチーム参戦
・ドット絵アセット全て自前で
・CloudBuildの活用
NOA's Project ・学生以外の方とチーム開発
・設計を考えて分業する
 (スキマんの時はほとんどアセット要員だったのでw)
・DoTweenに触れる

お題がちょうど「2」ということで2人対戦2人プレイなどが浮かび、オンラインゲームにすることにしました。

2つ目については、自分のキャラクター(chillballとkani-chan)を起用することで「kugiにしか作れないゲーム」を作ることにしました。

f:id:kugi_masa:20210530180643p:plain f:id:kugi_masa:20210530181023p:plain
chillballとkani-chan

chillballは私が日常を4コマで描いているkugi日記に登場したキャラクターです。

また、kani-chanは自分がまだUnityに触れたばかりの頃に大学の友人と2人でゲームを作ろうとした際に、その友人が打ってくれたドットです。 結局ゲーム完成には至りませんでしたが、Unityを使った開発の原点のような気持ちもあり、slackのstatusではkani-chanにいつも見守ってもらっています。 (勝手に借りてごめんよw🙏)

f:id:kugi_masa:20210530183737p:plain
Slackのユーザステータス

このように、挑戦したことのないオンラインゲームへ挑戦することでモチベーション維持を、また1人での開発だからこそできる自分らしさの盛り込みをすることで、モヤモヤは解消されました。

そして開発へ

そうして今回製作したのがKani と Uniです。 2分間の間でマッチングした2匹のKaniでUniをたくさん倒すゲームです。

unityroom.com

f:id:kugi_masa:20210530190125p:plain
Kani と Uni

オンラインゲームを製作するにあたって、私は今回オンライン対戦ではなく、オンライン協力で遊んでもらおうと思いました。 あえてオンライン協力を選んだのは、

u1wを通して偶然マッチングした人と一緒に協力をして楽しい体験が共有できたらめちゃくちゃエモいだろうなー

と思ったからです。

そういう意味でも今回はランキング機能を競わせるための要素ではなく、偶然マッチングした二人の名前が記録されるものという意味も込めて、モリー(Memories)と名付けました。

f:id:kugi_masa:20210530185957p:plain
モリー(Memories)

楽しさの共有ではEbiを収集アイテムとして散りばめて、Ebiをマッチングした二人で一定数集めたら無敵KaniになってUniを一掃するというEbi Dance機能をつけました。

chillballを起用したこともあり、全体的にchillな雰囲気を表現したのですが、EbiDance状態中は一変してUIを虹色に光らせてみたり、BGMもEDMっぽいものに変えたりと雰囲気をガラリと変えました。

この雰囲気の緩急とUniを一掃する気持ちよさを共有させたいという部分がこのKani と Uniに込めた私の想いです。

初めてのオンラインゲーム製作ではo8queさんの「PUN2(Photon Unity Networking 2)で始めるオンラインゲーム開発入門」にとても助けられました。 PUN2を初めて使う私でもオンラインゲームを作ることができたので、オンラインゲームに挑戦したい方にはおすすめの入門書です。 改めてこの場でお礼申し上げます。o8queさんありがとうございました!!!

zenn.dev

ちょうど最近4コマを描き始めたということもあり、画像アセットについては手書きで用意しました。

f:id:kugi_masa:20210530211533p:plain
手書きのアセット

バグから生まれる遊び

公開したはいいものの、マッチングしないと遊べない状態だととそもそも体験してもらいたいことを提供できないので、CPU(ドット絵kani-chan)を実装することにしました。

オンラインゲームでは通信の確認をするため、ゲームを2つ起動してテストをしなくてはなりません。 今回私は一度ビルドしたものとUnityEditor上で実行した2つのクライアントでテストをしていましたが、かなり効率が悪かったように感じます...。 この効率の悪さからも細かいところでバグを踏んでしまっていて、kani-chan実装にかなり苦労しました。

unity1week online共有会 #5のzizoさんの発表でもあったように、Unity Hub上で別プロジェクトとして登録してエディタを2つ起動することで快適に動作確認ができそうです👀

www.youtube.com

そして、なんとかkani-chanが投入でき、CPUモードでツイートした場合は

今度は Kani-chan 以外と遊びたいな...

の一文が追加されるようにしてみました。(気づいた人はいるだろうか...笑)

無事kani-chanも導入でき、事なきを得たかと思いきや...

部屋によってEbiが大量発生したり、Uniが無限に出たり、逆にEbiが全く出なくなったり

と、もはや誰かが「Kani と Uni」の生態系をいじっているのではという事態に...

しかし、ゲームの進行事態には問題がなく、部屋ガチャとして機能していたので 仕様としては残すことにしました。

Ebiの大量発生部屋は一部ではSSR部屋と呼ばれ、 盛り上がっていただけました笑

まっともぉんさんやぱふもどきさんのオンラインゲーム配信でも取り上げていただけて、 実際に遊んでる方の反応が見れたのはとても嬉しかったです。

youtu.be

また、nattuhanさんとつっちーさんにはNoa's ProjectのDiscordサーバーで通話をしながらテストプレイやデバッグをお手伝いしていただきました。 感謝です!!🙏

まとめ

参加するかどうかを最初は悩んでいましたが、やはり参加して本当に良かったです。 こうして毎回楽しく参加できているのも、主催のないちさんをはじめとする、u1wというお祭りに様々な形で関わっているみなさんあってこそだと思います。ありがとうございます!!!

私のKani と Uniへ込めた想いをしっかりとゲームを通して伝えることができたかは分かりませんが、 今回掲げていた2つの目標も大方達成できたと思います。 また、結果として初めて総合評価にランクインすることもできました。 プレイしてくださった皆さん、本当にありがとうございました!

次回もできる限り、前向きな気持ちで参加したいと思います。 それではまた!

2020年振り返り

はじめに

いよいよ年明けです。今年は特にはやかった気がします。

2020年の振り返りを書いていきたいと思います。

1月 〜ほとんど広島にいなかった〜

ちょうど就活の面接が始まった頃で、関東に行くことが多かったです。

友人が巣鴨に住んでいたので、いつも泊めてもらっていました。 ありがとう!!!!

enPiT2019のメンターをしていたので、広大チームの成果発表会のために筑波にも行きました。

kugi-masa.hatenablog.com

リアルタイムレンダリングについて学習するために、OpenGLチュートリアルとかもこの時期から少しづつやっていましたね。

2月 〜研究、就活にBlender

1/31~2/2 で開催されたGGJ広島2020に参加しました。

Global Game Jam 2020 in Hiroshima - connpass

お題は確かRepairで、私たちのチームは

壺を割ってくる勇者に壺を割られる前に壺を「修復」するゲーム

を作りました。

私はモデルとアニメーションを主に作成しました。

ある程度できたけど、あともう少しという感じで少し不完全燃焼だった記憶があります。takさん(@bgdaewalkman)と一緒に開発できたのでヨシ!!!

研究では中間発表が2月でした。中間発表と就活の面接x2が同じ週にあるという鬼ハードなスケジュールでしたが、なんとか乗り切りました。

年度が変わる前でもあったので研究室の大改造が行われていて、Blenderで改造後のイメージ構図を作成しウォークスルー動画を撮ったりもしました。

(今見るとLighting雑雑の雑)

この時期ハマってたドラマはMR.ROBOT🤖

3月 〜さよならFishy〜

2月末に1社内定をいただくことができたので、就活は第一志望を残すのみでだいぶ落ち着きました。

Unity1Week「逆」に参加しようと思っていましたが、2月が割と立て込んでいたのでこの回はスキップすることにしました。

Unity 1週間ゲームジャム お題「逆」 | フリーゲーム投稿サイト unityroom

Fishyという魚になって「逆」に釣られないようにするゲームを作っていました。 絶賛unityNweek中です!!!おそらくお蔵入りです笑

あとはどう森買ったり、モンテカルロ法で円周率計算するやつ作ったりしました。

4月 〜オンラインでいろいろ〜

新年度が始まりM2になりました。コロナの影響でオンラインイベントが増え、いろんなイベントに参加するようになりした。

また、昨年度まではあまり顔を出せていなかったHiCoderも、オンラインになったことで参加するようになりました。

高校の同期とZoomでオンライン飲み会が毎週金曜日に開催されるようになったり(私はあまり参加できていませんが今でも続いてる👀!!)

OpenGLで作った三角形🔺で遊んでみたり

Cammelでの新プロジェクトのためにFlutterはじめたり

CammelでLT会(MomijiLTの全身)をオンラインで開いてYouTubeLiveで配信してみたり

kugi-masa.hatenablog.com

インプットとアウトプットがいい塩梅の年度始まりでした。

5月 〜ハッカソンとLTと〜

5月はハッカソン(ゲームジャム)とLTにたくさん参加しました

レッドハッカソンオンライン2020では特別審査員賞をいただけました🎉

kugi-masa.hatenablog.com

また、前回参加できなかったunity1weekに参加して、共有会でも発表ができたのもよかったです!!(unity開発界隈の知り合いが増えました🙌)

そして、未来掴みました👍

6月 〜スクラム、チーム開発インプット月間〜

アジャイルスクラム界隈のイベントに参加しました。

『SCRUM BOOT CAMP THE BOOK 増補改訂版』出版記念イベント、そして4月ごろから数回参加していた分散アジャイルチームについて考える会に参加しました。

そして月末にはenPiTでお世話になったmiholoveさんのご厚意でいただいたスポンサーチケットでSCRUM FEST OSAKAに参加してきました。

kugi-masa.hatenablog.com

密度の濃ゆい凄まじいインプットばかりでした。

Cammelでの開発にも持ち帰って活かすことが少しはできたかな🤔

またこの時期からUUUOでのインターンも始まりました。

7月 〜就活と縄跳びの終わり〜

長かった就活が終わり、月初めに茶摘みをしました🍵 とてもいい経験になりました!!

また、4年半お世話になったMacBookAirとお別れをし、MacBookProを購入しました🎉

そして、縄跳びはこの日を境に途切れ、ZUMBAを家でするようになりました。(なお三日坊主)

8月 〜ハッカソン月間〜

8月はUnity1Week「ふえる」Open Hack U Vol.2に参加しました👨‍💻

github.com

この「ふえる」のu1wから他の方とランキングで競うことが多くなり、ハッシュタグを生やすなどしました。

あまりランキングに組み込めていませんが、真のu1wランカーズ目指して頑張りたいです😤

8月からCammel LTがHiCoderとコラボ開催になり、MomijiLTになりました!!🍁

youtu.be

9月 〜ハッカソン主催〜

9月はハッカソンを2つ(?)主催しました。

1つ目はカニハッカソン🦀

...という名目でインターン先のカニの在庫管理アプリの開発をスタートしました笑

kugi-masa.hatenablog.com

カニノケンカでも遊びました👍

ハッカソンは主催しましたよ!!笑👀

HU hackathon 2020 onlineというオンラインハッカソンを主催しました!!

kugi-masa.hatenablog.com

ISUCON10に出場したり、Unityゲーム開発者ギルドに参加したのも9月でした

scrapbox.io

10月 〜キーボード作った!!!〜

自作キーボード好きのラボメンの影響で、学生のうちに自作キーボードを作りたいと思っていたので、

ゆかりキーボードファクトリーさんのMint60を購入しました。

とても気に入っています😎

次のunity1weekに向けてaojilu君とSilCilさんとチームを組み始めたのもこの頃でしたね。

kugi-masa.hatenablog.com

10月からシェーダー芸の作品も少しづつ作っていきました。 また少しづつ学びながら作っていきたいですね〜

github.com

SPAJAM2020にも参加しました!!

11月 〜JPHACKSと学会〜

11月には今年からオンラインになったJPHACKSにCammel全員で参加しました🐫

kugi-masa.hatenablog.com

また、初の学会に参加し優秀論文賞をいただけました!!!🎉

12月 〜そして師走〜

Unityゲーム開発者ギルドの方の配信をみたりDiscordで雑談したり楽しい年の瀬でした。

Unity1Week「あける」には私たちチームaojiluも参加し、「すきすきスキマん」というゲームを作りました。

評価期間も1/10(日)までなので遊んでいただけると嬉しいです!!

unityroom.com

まとめ

今年もいろんな方に大変お世話になりました。

今年はコロナの影響でオンラインで何かをするのがとても多かったです。 オンラインになったことで、イベントに参加しやすくなってよかったです。 それでも来年こそはオフラインイベントにも参加したいですね。

来年からは社会人です!! 残りの学生期間、研究に開発、最後まで楽しみながら頑張りたいと思います💪

それでは来年もよろしくお願いいたします!!

カニから学んだこと

はじめに

こちらの記事は広島大学ITエンジニア Advent Calendar 2020 19日目の記事です。

私は今年の5月ごろから広島の株式会社ウーオという水産業界の流通をITで支える会社でエンジニアインターンをしています。

uuuo.co.jp

8月はじめから11月末にかけて、エンジニアインターン生の2人で始まったカニの在庫管理アプリプロジェクト「かにっこ」を一度クローズすることになりました。

こちらの振り返り記事ではプロジェクトの振り返りかにっこを通して学んだことについて共有したいと思います。

かにっこ

カニは鮮魚と違って、在庫として抱えることがあるから管理が大変」

この課題を解決するために「かにっこ」は始まりました。

まずはカニオペレーション(商品をセリ落としてからお客さんに出荷するまでの流れ)について学ばないといけないので、管理がどう大変なのかを切り出して考えることにしました。

  • カニは鮮魚とは異なり、セリ落とした商品をその日に出荷するだけでなく、UUUOの在庫として確保することがある。
  • また、在庫として確保されたカニは急にいなくなったり(脱出...)水死して売れなくなる場合がある。
  • カニには様々な規格や状態がある。
    • 例)
    • めちゃくちゃ多いです🦀
    • 同じ1番2番でも港によって規格が微妙に異なります。
  • 出荷の際、松葉ガニは枚数、セコガニはcs数(規格によって決まった枚数を1ケースとしてまとめて出荷する)で管理する。
    • 雌のカニのことをメガニまたはセコガニと呼ぶらしいです。
    • カニの数え方は1匹、2匹ではなく、1枚、2枚と数えます。

これらのことから、カニの在庫管理は鮮魚でのオペレーションと異なり複雑で大変になっていることがわかりました。

システム設計

今回はインターン生の2人でプロジェクトの立ち上げから設計、そしてリリースまでを任せていただけるという機会をいただきました。実際に使っていただく広島のオフィスにいらっしゃるセールスチームや港でセリに参加して商品をセリ落し出荷作業を行うベースチームの方々に対してヒヤリングを行ったり、オペレーションフローの情報を元に「かにっこ」がオペレーションのどこで使われるかを考え設計を進めていきました。

f:id:kugi_masa:20201214143723p:plain
オペレーションフローとかにっこ

以前までのUUUOの業務では私がFlutterを用いたフロントエンド実装、もう一人のインターン生がrailsを用いたサーバーサイド実装を主にしていました。今回のプロジェクトではお互いのスキルアップのためにもロールを途中で入れ替えて取り組みました。モブプロ形式も取り入れ、お互いの得意な方を相手に教えることで得意な方の実装への理解も深まりました。

また、Miroを使ってタスクの見える化言語化を行い、GitHub Issueで実際に着手する実装タスクの管理を行いました。

これまでCammelで行ってきた開発やハッカソンではFirebaseなどのBaaSを用いて実装していたので、バックエンド実装についてあまり考えずフロント実装に専念していました。しかし、今回APIの実装やデータベースの設計に触れることで、フロント側で呼び出したAPIのリクエストがサーバーサイドでどのように動くのかを知ることができとても良い学びになりました。

今後はサーバーサイドのことも考えてフロント実装に取り組んでいきたいと思います。

運用の難しさ

「かにっこ 」はファーストリリース(社内アプリなのでTestFlightでの内部リリース)まではできたものの、「かにっこ 」の運用までには至らず、結果としてプロジェクトをクローズすることになりました。

  • 実際にテスト運用してみると、モバイルよりPCでの入力の方が向いていた
  • 現在スプレッドシートで運用ができている
  • オペレーションのなかで変更の要望があったとき、アプリケーションでの実装よりも、スプレッドシートの修正の方が素早くカイゼンできる

以上の要因から今回クローズをすることにインターン生二人で決めました。

管理ができないままでは問題なので、セールスチームの方がスプレッドシートで管理シートを作成され現在はそちらでカニの在庫管理運用をしています。

カニのオペレーション以前から、ベースチームやセールスチームの皆さんにはお時間を取っていただいてアプリの壁あてにご協力いただきました。しかし、実際カニのオペレーションが始まりテスト運用をしていただく中で、現実的にオペレーションに組み込みづらい点や修正点が出てきました。そして、そこからの修正(主にデータベースの再設計)に時間がかかってしまいました。

今回得た学びは、課題をもっとシンプルに切り分けて小さい領域(MVP)でテストをする方が良いということです。実際にアプリを作っている段階では「一折、二折」といったカニの状態松葉ガニとセコガニの枚数とcs数の違いまで実装に組み込んでいましたが、実際にテスト運用をしてみると、カニが生きているかと水死しているかが一番重要で、カニの状態までは確認と管理している時間はありませんでした。また、松葉ガニとセコガニでの違いは管理する単位だけなので、最初は松葉ガニのみに絞ってテストしてみる方が早く修正し次のテストに取り掛かれたと思います。

f:id:kugi_masa:20201214150200p:plainf:id:kugi_masa:20201214150204p:plainf:id:kugi_masa:20201214150209p:plain
This is かにっこ

おまけ(カニハッカソン🦀)

「かにっこ」が始まった直後にちょうどLTをする機会があったので、「カニをハックしてみた」という題で発表をしました笑。 スライドを以下に掲載します!!

speakerdeck.com

まとめ

結果としてはクローズしてしまったプロジェクトになってしまいましたが、実際に使ってもらえるユーザがいる状態で一からプロジェクトを立ち上げて実装する機会をいただくことができて本当によかったです。

また、プロジェクトのクローズと運用の難しさを学生のうちに経験することができました。 もちろん悔しさもありますが、その分学びも大きかったです。

サポートしていただいたUUUOエンジニアの土谷さんをはじめ、ヒアリング、壁あてにご協力してくださったセールスチーム、ベースチームの皆さんありがとうございました。

f:id:kugi_masa:20201214150352j:plain
Thank you Kanikko

やったこと

  • インターン生2人でプロジェクト立ち上げからクローズまで経験した。
  • カニについて学んだ。

わかったこと

  • 松葉ガニだけでもめちゃくちゃ分類される。
  • カニめちゃ高い...!!
  • 作る側も、使う側も実際に使う状況になるまでわからないことは多い

次やりたいこと

  • サーバーサイド実装の力もさらに付けていきたい。
  • Flutter for Web気になる。