透明度グラデーションの与え方(three.js)
「xy平面上の格子点で与えられたz値をもつ格子状オブジェクトへのテクスチャマッピング(three.js)」に続いて、本項はthree.jsを用いて3次元グラフィックスに登場するオブジェクト(ポリゴン)を半透明にする方法を解説します。 透明度ではなく配色をグラデーションにしたい場合、オブジェクトの頂点座標ごとに描画色を与えることで実現することができます。 一方、オブジェクトを半透明にしたい場合、オブジェクト全体を均一の透明度を指定することができますが、頂点ごとに透明度を与えることができません。 では、どのようにすればよいかというと、透明度が定義された画像(PNG形式など)を用いたテクスチャマッピングです。次のプログラムでは、画像データをcanvas要素を用いて生成しています。
3次元オブジェクトの生成方法
var N = 100; var width = 1; var specifyZ = { //z値の指定 enabled : true, function : function( x , y ){ return 50*Math.exp( - ( x * x + y * y ) / 200 ); } }; var specifyColor = { //color値の指定 enabled : false, function : function( x , y ){ var w = 0.9 * Math.exp( - ( x * x + y * y ) / 200 ) + 0; return { r: 1, g: 1, b: 1, a : w }; } } var vertices = []; var colors = []; var faces = []; var canvas_colors = []; //テクスチャマッピング用 for ( var i = 0; i <= N; i++ ) { for ( var j = 0; j <= N; j++ ) { var x = ( -N / 2 + i ) * width; var y = ( -N / 2 + j ) * width; //初期条件を与える var z = 0; if( specifyZ.enabled ){ z = specifyZ.function( x, y ); } else { z = 0; } //頂点座標データの追加 vertices.push( new THREE.Vector3( x, y, z ) ); if( specifyColor.enabled ) { colors.push( specifyColor.function( x, y ) ); } } } for ( var i = 0; i < N; i++ ) { for ( var j = 0; j < N; j++ ) { var ii = ( N + 1 ) * i + j; //面指定用頂点インデックスを追加 faces.push( [ ii, ii + ( N + 1 ), ii + ( N + 1 ) + 1 ] ); faces.push( [ ii, ii + ( N + 1 ) + 1, ii + 1 ] ); } } //形状オブジェクトの宣言と生成 var geometry = new THREE.Geometry( ); //形状オブジェクトに頂点座標の設定 for( var i = 0; i < vertices.length; i++ ){ geometry.vertices.push( vertices[i] ); } //面指定配列とテクスチャ座標の設定 for( var i = 0; i < faces.length; i++ ){ if( specifyColor.enabled ){ var _colors = [ colors[ faces[i][0] ], colors[ faces[i][1] ], colors[ faces[i][2] ] ] } else { var _colors = null; } geometry.faces.push( new THREE.Face3( faces[i][0], faces[i][1], faces[i][2] , null , _colors) ); var v1 = vertices[ faces[i][0] ]; var v2 = vertices[ faces[i][1] ]; var v3 = vertices[ faces[i][2] ]; geometry.faceVertexUvs[ 0 ].push( [ new THREE.Vector2( (v1.x + N/2)/N , (v1.y + N/2)/N ), new THREE.Vector2( (v2.x + N/2)/N , (v2.y + N/2)/N ), new THREE.Vector2( (v3.x + N/2)/N , (v3.y + N/2)/N ) ] ) } //面の法線ベクトルを計算 geometry.computeFaceNormals( ); //面の法線ベクトルから頂点法線ベクトルの計算 geometry.computeVertexNormals( ); function generateTexture( width, height ) { //canvas要素の生成 var canvas = document.createElement('canvas'); //canvas要素のサイズ canvas.width = width; //横幅 canvas.height = height; //縦幅 //コンテキストの取得 var context = canvas.getContext('2d'); //ビットマップデータのRGBAデータ格納配列 var bitmapData = []; //RGBAデータ格納配列への値の代入 for ( var t = 0; t < canvas.height; t++ ) { for ( var s = 0; s < canvas.width; s++ ) { var index = ( t * canvas.width + s) * 4; //各ピクセルの先頭を与えるインデクス番号 var x = (s - canvas.width/2)/canvas.width * N; var y = (t - canvas.width/2)/canvas.width * N; var color = specifyColor.function( x, y ); //ビットマップデータのRGBAデータ bitmapData[index + 0] = 255 * color.r; //R値 bitmapData[index + 1] = 255 * color.g; //G値 bitmapData[index + 2] = 255 * color.b; //B値 bitmapData[index + 3] = 255 * color.a; //A値 } } //イメージデータオブジェクトの生成 var imageData = context.createImageData(canvas.width, canvas.height); for ( var i = 0; i < canvas.width * canvas.height * 4; i++ ) { imageData.data[i] = bitmapData[i]; //配列のコピー } //イメージデータオブジェクトからcanvasに描画する context.putImageData(imageData, 0, 0); return new THREE.Texture( canvas ); } //材質オブジェクトの宣言と生成 var material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent : true }); //平面オブジェクトの生成 plane = new THREE.Mesh(geometry, material); //平面オブジェクトのシーンへの追加 scene.add(plane); //平面オブジェクトの位置座標を設定 plane.position.set(0, 0, 0); plane.material.map = generateTexture( 256, 256 ) ; plane.material.map.needsUpdate = true;
参考図書
3次元グラフィックス関連
・three.jsによるHTML5グラフィックス上 【改定版】
・three.jsによるHTML5グラフィックス下 【改定版】
・three.jsによるHTML5 3Dグラフィックス 【新機能と応用】