MarchingCubes.jsでメタボールを表現(Three.js[r145]を使用)
Three.jsでマーチンキューブ(MarchingCubes.js)を使うとポリゴンによるメタボールの表現が可能です。
<script src="./three_r145/three.min.js"></script>
<script src="./three_r145/OrbitControls.js"></script>
<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>