Three.jsとMarchingCubes.jsでメタボールを表現!滑らかな3Dオブジェクトをポリゴンで生成
Three.jsとMarchingCubes.jsを使って、メタボールをポリゴンで滑らかに表現!
インタラクティブな視点回転を加え、リアルな3Dオブジェクトを生成する方法を解説します。
WebGLを活用した3Dコンテンツ制作に最適な技術を、ソースコードと実例で詳しく紹介!
使ってみた限りでは球のみしか扱えないようです。
<script src="./three_r145/MarchingCubes.js"></script>
のようにしてマーチンキューブが使えるようにします。
マウス左ドラッグやパンで視点回転します。
<canvas id="can" style="width:1000px; height:600px; max-width:calc(100vw - 36px);max-height:calc((100vw - 36px) * 60 / 100);margin:0;padding:0;cursor:grab;" width="1000" height="600"></canvas>
<script src="./three_r145/three.min.js"></script>
<script src="./three_r145/OrbitControls.js"></script>
<script src="./three_r145/MarchingCubes.js"></script>
<script>
var balls=[];
var scene,camera;
var SphereMesh;
var main = function () {
//■シーンを作成
scene = new THREE.Scene();
//描画先canvasを取得
let can=document.getElementById('can');
//canvasの高さ,幅を取得
let w = parseInt(can.style.width);
let h = parseInt(can.style.height);
//■カメラを作って設定
//THREE.PerspectiveCamera( 画角(度), アスペクト比, カメラに写る最短距離, カメラに写る最長距離 );
camera = new THREE.PerspectiveCamera( 50, w/h, 1, 10000 );
camera.position.set( 0, 0, 2000 );//カメラの位置を設定
camera.rotation.set(0,0,0); //カメラの回転角を設定
//camera.lookAt(new THREE.Vector3(0, 0, 0));
scene.add( camera );
//■レンダラーをDOM(canvas)上に設置する
renderer = new THREE.WebGLRenderer({canvas:can , antialias: true});//アンチエイリアスをtureにする
renderer.setSize( w, h );
//■光源------------------------------------------------
//環境光(すべての物体にすべての方向から与える光)光の当たらない部分でも真っ黒にならない
var AmbientLight=new THREE.AmbientLight(0xffffff,0.4);
scene.add( AmbientLight );
//スポットライト 色, 強さ,距離,角度(angle),半影[0-1],減衰[1,1]
const spotLight=new THREE.SpotLight(0xffffff, 2,3000,Math.PI/4, 0.8, 1);
//(x→, y↑, z手前)
spotLight.position.set(100,1000,1500);
spotLight.target.position.set(0,0,0);
scene.add(spotLight);
scene.add(spotLight.target);
//■テクスチャマッピング用画像のロードと設定
//球体に貼り付けるテクスチャ画像のロード
let Texture360=new THREE.TextureLoader().load('./three_r145/img/360.jpg');
Texture360.wrapS=THREE.RepeatWrapping;
Texture360.wrapT=THREE.RepeatWrapping;
//テクスチャの繰り返し回数を指定する
Texture360.repeat.set(1,1);
//球体用の基本マテリアルを作成する
let SphereMaterial=new THREE.MeshBasicMaterial({
color:0xFFFFFF,
side:THREE.BackSide,//両面を表示する設定
map: Texture360
});
//球体ジオメトリの作成(半径、横分割数,高さ方向分割数)
let SphereGeometry=new THREE.SphereGeometry(1,32,24);
//球体のメッシュの作成
SphereMesh=new THREE.Mesh(SphereGeometry,SphereMaterial);
SphereMesh.scale.set(5000,5000,5000);
scene.add(SphereMesh);
// キューブマップ
//■反射マッピング用のターゲット作成
cubeRenderTargetReflection = new THREE.WebGLCubeRenderTarget(512,{
generateMipmaps: true,
minFilter: THREE.LinearMipmapLinearFilter });
cubeRenderTargetReflection.texture.mapping = THREE.CubeReflectionMapping;//反射マッピングに設定
//■反射マッピング用キューブカメラの作成
//(カメラに写る最短距離, カメラに写る最長距離 ,ターゲット)
cubeCameraReflection = new THREE.CubeCamera( 0.1, 100000, cubeRenderTargetReflection);
//■反射材質の作成
let materialReflection=new THREE.MeshLambertMaterial({
color:0xffffff,
envMap:cubeCameraReflection.renderTarget.texture,
reflectivity:0.8, //反射率
});
//■MarchingCubesインスタンスの作成
//(resolution:値を大きくするほど滑らかな描画20~100, material, enableUvs, enableColors, maxPolyCount)
effect = new THREE.MarchingCubes( 64, materialReflection, true, true ,100000);
effect.position.set( 0, 0, 0 );
effect.scale.set( 1000, 1000, 1000 );
//effect.isolation=80; //分離???
scene.add(effect);
//メタボールの準備
for(let i=0;i<20;i++){
balls[i]=[];
balls[i].x=Math.random()*0.8;
balls[i].y=Math.random()*0.8;
balls[i].z=Math.random()*0.1+0.5;
balls[i].vx=Math.random()*0.01-0.005;
balls[i].vy=Math.random()*0.01-0.005;
}
//マウスの左右ドラッグ+中ボタンの上下ホイールで動かす
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0,0,0);
controls.enablePan=false; //パンできなくする
controls.enableZoom=false;//ズームできなくする
controls.update();
renderLoop();
};
function renderLoop () {
setTimeout(renderLoop,33);
effect.reset();//リセット
for(let i=0;i<balls.length;i++){
if((balls[i].x+balls[i].vx)>0.8){balls[i].vx=-balls[i].vx;}
if((balls[i].x+balls[i].vx)<0.0){balls[i].vx=-balls[i].vx;}
if((balls[i].y+balls[i].vy)>0.8){balls[i].vy=-balls[i].vy;}
if((balls[i].y+balls[i].vy)<0.0){balls[i].vy=-balls[i].vy;}
balls[i].x+=balls[i].vx;
balls[i].y+=balls[i].vy;
// x,y,z(0~1),連結強さ,減衰, 色
//addBall(x,y,z,strength,subtract,colors)
//半径=sqrt(連結強さ÷減衰) となるらしい
effect.addBall(balls[i].x+0.1, balls[i].y+0.1, balls[i].z, 1.6, 100);
}
effect.update();
SphereMesh.visible=true;
effect.visible=false;
cubeCameraReflection.update(renderer,scene);
effect.visible=true;
SphereMesh.visible=false;
renderer.render( scene, camera );
}
window.addEventListener( 'DOMContentLoaded', main, false );
</script>
