BLOGワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。アルゴリズムあけましておめでとうございます、エンジニアの成田です。本年もよろしくお願いいたします!それでは早速ですが、今回のブログはdemosceneのintroという分野について紹介させて頂きます。demosceneとは小さいサイズのプログラムを特徴とする非インタラクティブな映像(と場合によっては音楽も)作品を表示するコンピュータアート文化で、中でもintroはその実行ファイルサイズに4kバイトや64kバイトなどの上限を設けたサブカテゴリのことです。intro作品でこういうものがありました。もの凄いですよね、このクオリティのものを4kのプログラムで書くというのですからもうエクストリーム・スポーツのようなものです。このElevatedはなんでも4kバイトの制限を超えるためにジオメトリのみならず、テクスチャやBGMを起動時に生成しているとか。intro」などのキーワードで検索すると素晴らしい作品がたくさん出てきます。私もこの分野は完全に見る側で作り方は全然詳しくないのですが、この機会にちょっと勉強をして初歩的なプログラムを作って動かしてみました。今回はintroのファイル制限にも目を瞑ることにします(笑)1.レイマーチングintroでよく用いられるアルゴリズムとして、レイトレーシングの一手法であるレイマーチングがあります。introではCPU側からシーンに表示するオブジェクトのポリゴンの頂点情報等を渡すことはあまり行いません。ファイルサイズの制限というルール上、事前にモデリングしたオブジェクトやテクスチャを持つことは難しいためです。そこでポリゴンでなく、数学的な式からオブジェクトをレンダリングできるレイマーチングが用いられるわけです。functionがあります。これらについて少し説明します。Tracing)は幾何学的な距離を利用してオブジェクトのサーフェイスを検出するアルゴリズムです。スフィアトレーシングのアルゴリズムはそれほど難しくなく、ざっくりと言えば「現在のレイの到達点」という概念があり、反復計算によって特定長のレイを継ぎ足していくイメージです。具体的には以下のような手順をとります。視点からレイトレースをスタート。現在のレイ到達点は視点。レイ到達点から最近傍のオブジェクトまでの距離を計算し、レイの方向へ同じ長さだけレイを継ぎ足す。2の手順を特定回反復する。最後に取得した最近傍オブジェクト距離が十分に小さい場合はオブジェクトに衝突したと見なす。なければ衝突しなかったと見なして計算終了。functionです。引数として現在のレイの到達点を受け取り、シーンのオブジェクトのうちで最近傍のオブジェクト(のサーフェイス)までの距離を返すわけです。functionは次のようになります。意外と単純な式で表せます。実際に検算してみると数学的に正しいことが分かると思います。アフィン変換的なこともできます。moreにまとまっているので、興味があれば見てみてください。それではこれらを実際に実装してみます。ESで動かしてみました。2.0の記事を参照してください。今回はシェーダ部分のみソースコードを載せることにします。準備としてレンダリングに都合が良くなるように座標系の正規化を行います。スクリーン中央が(0,0)、左下が(-1,-1)、右上が(1,1)となるような座標系です。座標系の正規化が正しく行われているか試しに出力してみます。今回は一般的なポリゴンによる3D表示は行いませんので、ポリゴンは単純に画面全体((-1,-1)〜(1,1)の領域)に張ります。射影変換も行いません。このポリゴンをレンダリングして、主にフラグメントシェーダで好きな絵になるように弄っていくわけです。バーテックスシェーダはほとんど何もしていません。フラグメントシェーダは以下。u_resolutionはCPUから渡したOpenGLサーフェイスのサイズです。画面左下が(-1,-1)、右上が(1,1)となる座標系。想定通りに座標系の正規化が行えたようです。それでは次はレイトレーシングの準備としてカメラとレイを定義します。3.0)で原点方向に向けたものとします。テスト出力してみましょう。カメラとレイが定義されていれば上のような出力になります。それではいよいよオブジェクトを出してみます。functionを定義してみます。あとカメラもちょっとずらします。球を出すことができました。レイマーチングできているようです。この絵ではちょっと寂しいのでランバート反射のシェーディングを行ってみます。ランバート反射を行うためには法線ベクトルが必要ですが、今回は通常のポリゴン描画のように頂点情報がもらえませんのでシェーダーで自力で法線ベクトルを検出しなければなりません。functionの傾斜を検出する方法を利用します。各軸方向にある種の微分をしているような感じになるんだと思います。結果ランバート反射によるシェーディングができました。functionをかませることで球をいっぱい出してみます。画面奥方向へも図形が反復するので、奥を描画するためにレイマーチングの反復回数を倍にしましょう。結果なんかいっぱい出た!今回はこの辺で。機会があればもう少し豪華にしてみたいですねー。採用情報ワンダープラネットではモバイルゲーム開発者を募集しております。(S編)C/C++でネットワークプログラミングをやってみよう(2)スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。