Everyday Pieces ::
  • Webサービス
  • ブログパーツ
  1. ホーム
  2. プログラミング

three.jsで遊んでみる(15)

2013年12月26日 2013年3月15日 プログラミング MMD, three.js

MMDでサポートされてるけど
まだ対応してなかったスフィアマップをやってみました。

スフィアマップというのは、
テクスチャの貼り方の技法の一つで、
環境マッピングとか呼ばれてます。
擬似的な周囲環境の映り込みを再現する手法で、
金属のような光沢とかを表現できたりします。

環境マッピングの実装方式には、
球状マップ(sphere map)やキューブマップ(cube map)があります。
three.jsのサンプルである
こちらやこちらでその結果をみることができます。

three.jsのサンプルで見れたりするくらいなので、
割りとアッサリ導入できると思ってたんですが、
webGLレンダラーではスフィアマップはまだ実装されてませんでした・・・。
canvasレンダラーでは実装されているのですが、
webGLレンダラーではキューブマップのみとなってました。

ということで、
自前で実装することにしました。
どうやればいいかググってみたら、
これ(その1)やこれ(その2)とかみつかりました。
実現手法は一つでは無いようですね。
どっちがいいんだろ。
2つともやってみることにしました。

なお、
MMDのスフィアマップではマッピング時の演算として
乗算および加算をサポートしています。
今回は乗算のみの対応となっていますが、
fragment shader の最後の乗算を加算にするだけのことですね。たぶん。

GLSLなコードは以下の様な感じになりそうです。

その1)

// vertex shader
varying vec3 vNormal;
varying vec2 vUvSphere;
vNormal = normalMatrix * objectNormal;
vUvSphere.x = vNormal.x * 0.5 + 0.5;
vUvSphere.y = vNormal.y * 0.5 + 0.5;

// fragment shader
varying vec2 vUvSphere;
uniform sampler2D mmdSphereMap;
gl_FragColor = gl_FragColor * texture2D( mmdSphereMap, vUvSphere );

その2)

// vertex shader
varying vec3 vNormal;
varying vec2 vUvSphere;
vNormal = normalMatrix * objectNormal;
vec4 mvPosition = modelViewMatrix * vec4( objectPosition, 1.0 );
vec3 r = reflect( normalize(mvPosition.xyz), vNormal );
float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) );
vUvSphere.x = r.x/m + 0.5;
vUvSphere.y = r.y/m + 0.5;

// fragment shader
varying vec2 vUvSphere;
uniform sampler2D mmdSphereMap;
gl_FragColor = gl_FragColor * texture2D( mmdSphereMap, vUvSphere );

つづいて、three.jsを改造します。

three.jsで使われているGLSLなコードをダンプしてみると
こんな感じになっています。
レンダラーやマテリアルのプロパティに応じて、
例えば

#define USE_SKINNING

とかが、
GLSLのソースコードに付加される仕組みになっています。
ただ、現状の実装では
three.jsが認識しているプロパティでないとうまく行きません。
そこで、マテリアルに

material.vertexShaderPrefix
material.fragmentShaderPrefix

というプロパティを追加して対応することにしました、
改造したtheee.jsのコードは以下のようになります。
独自の #define とかをコードの先頭に追加できるようにしてしまうわけです。

// WegGLRenderer:
this.initMaterial = function ( material, lights, fog, object ) {
	.
	.
	
	material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, parameters, material.fragmentShaderPrefix, material.vertexShaderPrefix ); // MOD
	.
	.
};
function buildProgram ( shaderID, fragmentShader, vertexShader, uniforms, attributes, parameters , fragmentShaderPrefix, vertexShaderPrefix) { // MOD
	var p, pl, program, code;
	var chunks = [];

	// Generate code
	if ( shaderID ) {
		chunks.push( shaderID );
	} else {
		chunks.push( fragmentShaderPrefix ); // ADD
		chunks.push( fragmentShader );
		chunks.push( vertexShaderPrefix ); // ADD
		chunks.push( vertexShader );
	}
	for ( p in parameters ) {
		chunks.push( p );
		chunks.push( parameters[ p ] );
	}
	code = chunks.join();
	// code = md5(code); // to do if possible
	.
	.
	// ADD
	if (fragmentShaderPrefix) {
		prefix_fragment += fragmentShaderPrefix;
	}
	if (vertexShaderPrefix) {
		prefix_vertex += vertexShaderPrefix;
	}

	var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
	var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );
	.
	.
}

さて、
実際にやってみた感じでは、
その1)でも、その2)でもそれなりにイイ感じになったのですが、
MMDのスフィアマップ用に使用しているテクスチャとの相性が良さそうなのは
その1)っぽい気がしましたので、そちらを採用してみました。
ということで、
メタルっぽくなったミクさんはこちらです。

諸般の事情でちょっとローディングに時間がかかりますが、しばらく待ってみてください。なお、ChromeなどのWebGL対応のブラウザで見てください。PCパワーもそれなりに必要となるかもしれません。あまりにも時間がかかり過ぎるようならば、リロードして再度試してみてください。

mytest18

関連記事
three.jsで遊んでみる(46) GlslCanvasを使ってみた three.jsで遊んでみる(45) three.jsで遊んでみる(44) three.jsで遊んでみる(43) three.jsで遊んでみる(42) three.jsで遊んでみる(41) three.jsで遊んでみる(40) three.jsで遊んでみる(39) three.jsで遊んでみる(38) three.jsで遊んでみる(37) three.jsで遊んでみる(36) three.jsで遊んでみる(35) three.jsで遊んでみる(34) three.jsで遊んでみる(33) three.jsで遊んでみる(32) three.jsで遊んでみる(31) three.jsで遊んでみる(30) three.jsで遊んでみる(29) three.jsで遊んでみる(28) three.jsで遊んでみる(27) three.jsで遊んでみる(26) three.jsで遊んでみる(25) three.jsで遊んでみる(24) three.jsで遊んでみる(23) three.jsで遊んでみる(22) three.jsで遊んでみる(21) three.jsで遊んでみる(20) three.jsで遊んでみる(19) three.jsで遊んでみる(18) three.jsで遊んでみる(17) three.jsで遊んでみる(16) three.jsで遊んでみる(14) three.jsで遊んでみる(13) three.jsで遊んでみる(12) three.jsで遊んでみる(11) three.jsで遊んでみる(10) three.jsで遊んでみる(9) three.jsで遊んでみる(8) three.jsで遊んでみる(7) three.jsで遊んでみる(6) three.jsで遊んでみる(5) three.jsで遊んでみる(4) three.jsで遊んでみる(3) three.jsで遊んでみる(2) three.jsで遊んでみる

コメントする キャンセル

アドレスが公開されることはありません。が付いている欄は必須項目です。

投稿ナビゲーション

消費電力をモニターできるワイヤレスな電力計
国内Webサーバーの大規模改ざん発生中!

カテゴリー

WordPress つぶやき トピック プログラミング

タグ

AS3 enchant.js FamilyTreeVis Flash Geolocation gif.js kinect Linux MMD MoneyTrackNote notifier.js OpenCV PDFカレンダー RISC-V three.js セキュリティ テーマ自作 ブログパーツ 動物 動画 麻雀

アーカイブ

© Everyday Pieces ::