2019の16日目の記事です。2019に書こうと思っていたんですが、すでに埋まっていたので。Calendarです。Three.jsメインの場合は[Three.jsアドベントカレンダー](qiita.com前々からWebGLをレイマーチングではなく、ポリゴンによるメタボール表現をやってみたかったんですが、調べていたらどうやらマーチングキューブというものを使えばできるというところまでたどり着いたので、やってみました。Wikipediaja.wikipedia.orgどうやら以下のアルゴリズムが有名らしいです。素晴らしい記事が上がっていたので、主に以下の記事を参考にさせていただきました。Qiitaマーチングキューブ法はボクセルデータからメッシュを作成する手法です。空間を格子上に分割することで作成された各直方体(セルqiita.comあと、以下の記事も非常にわかりやすい説明でした。有限会社ホワイトラビット公式サイトボクセルデータからポリゴンデータに変換するアルゴリズム、マーチングキューブ法について解説します。サーフェイスレンダリングでwhite-rabbit.jpマーチングキューブはめちゃくちゃざっくりいうと、3次元ボクセルデータをポリゴンデータに変換するものです。各ボクセルは値を持っており、そのボクセル値によってセルの辺上にどのように頂点を配置するかが決まり、その頂点によってポリゴンの面が作られます。超えるか超えないかによって決まります。これはセル内のポリゴンの張り方を示した図です。15種類ですが、表裏を考えると256通りになります。しないを出し分けます。セルの分割数を増やすと、結構すぐ重たくなります。その頂点の配置の仕方256通りを予めルックアップテーブルとしてデータ化し、参照できるようにしておくアルゴリズムらしいです。ポリゴンの頂点が存在する場合、セルの辺を構成する2つのボクセル値によって辺上のどの位置に頂点が配置されるかも決まります。実装してみたのがこちら↓です。色をいじれるようになっています。※注意※numMarchingSegmentsとnumSpheresを増やしすぎると激重になります!たまに上下左右が切れているように見えるのは、マーチングキューブの空間からはみ出しているからです。描画したい球が、セルのないエリアに飛び出しているため、ポリゴンがないため描画できません。ソースコードはこちら↓。Contributegithub.comこの実装では、各ボクセル値を決定するのに、レイマーチングで使用するような距離関数を使用して、メタボールを実現しています。セルの頂点を始点としたときの、描画したいオブジェクトの距離関数の値がそのままボクセル値になっており、等面閾値は0になります。(要はセルの頂点が描画したいオブジェクトの内側に入るか、外側に出るかを判断したいため。1.0で記述しています。ソースコードの抜粋を見てみます。頂点の配置方法のルックアップテーブルのデータをテクスチャで生成する部分です。three.jsではDataTextureクラスという便利なものがあるので、それを使います。1のテクスチャに書き込みます。16の配列となっており、かつedgeTableというルックアップテーブルも使用して最終的な頂点の配置方法を参照していますが、@aa_debdebさんの実装ではtriTableを1次元の配列にし、edgeTableも廃して計算をシンプルにしています。(省略するとTHREE.UnsignedByteTypeとなる)、typeはTHREE.AlphaFormatにしておけば、データ書き込みの際にテクセルごとに1要素だけで済みます(THREE.RGBFormatだと、RGBの3要素分のデータが必要)。シェーダ側で値を参照するときはtexture2D関数の戻り値のa要素を参照すれば、値が取り出せます。1の範囲で格納されているので、255をかければ、もとの値が取り出せます。255.0;言い忘れていましたが、ルックアップテーブルで-1となっている値は、255としています(符号なしのため)。1.0だとビット演算子が使用できないので、定義しています。こちらのコードではcubeIndexをfloatで定義しているので、intにキャストしています。1);と書き換えられます。このアルゴリズムだとif文が多用されるんですが、あまり良くないとのことなので、step関数を使った記述に変えてみました。(Dat.GUIの一番上の値を動かしてみてください)追加してますが、今回の本質とは関係ないので説明を割愛します。エフェクトは↓のような感じ。effect.ホムンクルスさんのキービジュアルで使用しているようなボクセル風エフェクト。2019また、距離関数の詳細も詳しくは説明しませんが、numSpheresで渡ってきた数の分、ランダムに動く球を合成しています。ランダムな動き方は、randomValuesというuniform変数に、球の個数分のvec4にJavascript側で生成したランダムな値が入っているので、それを使用して適当に動かしています。フラグメントシェーダでは、頂点シェーダから法線と頂点を破棄するかどうかの値を渡して、破棄する場合はdiscardし、描画する場合はフォンシェーディングで色を付けてます。}}あとはそこまで大きく変わらないです。全貌はGitHubのソースコードを見ていただければと思います。↓こちらの記事でもマーチングキューブでメタボールを実装しているようなのですが、まだちゃんと読み込んでないとはいえ、どういう実装かよくわかってないです。2016](http://qiita.qiita.com・・・WebGLでマーチングキューブの需要があるかどうかは怪しいですが、自分なりに解釈して説明してみました。記事に書くことによって理解が深まったので、個人的には満足しています。実はQiitaのアドベントカレンダーに初参戦でした。(noteに書いてますが。)長くなってしまいましたが、以上です。最後まで読んでいただきありがとうございます。ダウンロード#tech#CreativeCoding#WebGL#GLSL#threejsこの記事が気に入ったら、サポートをしてみませんか?気軽にクリエイターを支援できます。サポートいただければ、レッドブルを飲んでより頑張れると思います。サポートをする「スキ」を押してクリエイターを応援しよう!ありがとうございます!あなたの「スキ」が力になります。(unshift)東京でフリーランスのdeveloperをやっています。Plugins82Tribakoありがとうございます!あなたの「スキ」が力になります。