【Three.js】Glass material and Broken glass

Three.js

 Three.jsのMeshPhysicalMaterialを使って、ガラスのマテリアルを作りながら、ガラスの破片が舞い落ちるSampleDemoにあるようなものを作って行こうかと思います。

MeshPhysicalMaterialの備忘録も兼ねてブログにしてみました。もしよろしければチャレンジしてみてください。

【Sample Demo】https://misora.main.jp/glass2/

【作品サイト】https://misora.main.jp/glass/

1.Glass Material (MeshPhysicalMaterial)

 Three.jsのMeshPhysicalMaterialを使って、反射を再現していきます。MeshPhysicalMaterialには、リファレンスにあるように、さまざまなパラメータがあるので、パラメータを調整できるデモサイトを作りました。ぜひご利用ください。

MeshPhysicalMaterial|Misora Ryo Experimental Worlds
Three.jsのMeshPhysicalMaterialのパラメータ調整サイト
three.js docs
MeshPhysicalMaterial – threejs.org
MeshPhysicalMaterial - Three.js Tutorials
sbcode.net

反射素材としてHDRIを使用します。以下のサイトなどから、HDRI素材のダウンロードをお願いします。サイズは1Kで十分だと思います。

Poly Haven • Poly Haven
The Public 3D Asset Library
Industrial Sunset (Pure Sky) HDRI • Poly Haven
Download this free HDRI from Poly Haven
polyhaven.com

three.js

HDRIの設定(反射に使用します)

import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
const scene = new THREE.Scene()
scene.background = new THREE.Color('#222');

// HDRI
new RGBELoader().setPath( './' ).load( 'industrial_sunset_puresky_1k.hdr', function ( texture ) {
	texture.mapping = THREE.EquirectangularReflectionMapping;
	scene.background = texture;
	scene.environment = texture; // <= 必須
});

MeshPhysicalMaterial(ガラス素材なのでtransmission=1.0)

const material = new THREE.MeshPhysicalMaterial({
  //envMap: new THREE.TextureLoader().load("sample.png"),  
  color: 0xffffff,
  //
  roughness: 0.0,
  metalness: 0.0,

  //クリアコート層の強度
  clearcoat: 1.0, // Default:0.0, max:1.0
  clearcoatRoughness: 1.0, // Default:0.0, max:1.0
  //clearcoatMap : new THREE.TextureLoader().load("sample.png"),

  //非金属材料の屈折率
  ior: 1.1,  //from 1.0 to 2.333. Default is 1.5
  //
  reflectivity: 0.01, // Default:0.0, max:1.0
  // 
  iridescence: 1.0, // 強度 Default:0.0, max:1.0
  iridescenceIOR: 1.0, // 虹の屈折率 Default is 1.3 1.0~2.33  1.3
  
  //光沢層の強度、
  sheen: 1.0, // Default:0.0 max:1.0  0.1
  sheenRoughness: 0.0, 
  sheenColor : 0xFFFFFF,

  //鏡面強度
  specularIntensity : 10.0, // 1.0
  specularColor : 0xFFFFFF,
  //specularColorMap :new THREE.TextureLoader().load("sample.png"),

  // 厚み
  thickness:10.00, //
  //thicknessMap: new THREE.TextureLoader().load("sample.png"),
  
  //伝搬
  transmission: 1.0, // <= ガラス
  //transmissionMap: new THREE.TextureLoader().load("sample.png"),

  //
  transparent: true,
  opacity: 1.0,
  wireframe: false,
});

テスト用のBoxGeometryの作成

const geometry = new THREE.BoxGeometry( 3, 3, 0.1 ); 
const cube = new THREE.Mesh( geometry, material ); 
cube.position.set(0,0,0);
scene.add( cube );

画像にあるようなサイトができると思います。マテリアルの微調整は、デモサイトから数値を調整する等で、お好みなものに調整してください。

2.Broken Glass Object

 Blenderを使って、下のような割れたガラスのようなオブジェクトを作成します。

Blender のアドオン「Cell Fracture」を有効化

Blenderのアドオンの「Cell Fracture」を使って作成します。まずアドオンを有効にしましょう。

ガラスのように薄いCubeを作成する

編集モードで細分化します。横・縦にのみ、幅には細分化しないでください。

Cell Fractureで分割

オブジェクト > クイックエフェクト > Cell Fracture で起動

ノイズ:1、再帰:1 でOKを押す。(実行)

giTFで出力

Three.jsで使えるように、.glbファイル(glass.glb)で出力しましよう。(圧縮で出力するとDRACOLoaderが必要になります)

出力できれば、OKです!(glass.glb)

3.Three.jsで表示させる(マテリアルと組み合わせる)

 three.jsでガラスオブジェクトの.glbファイル(glass.glb)を読み込んで、マテリアルを適用させていきましょう

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
// import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
let modelSet = false; //モデルの読み込みが完了したかのフラグ
let GlassObject;

const loader = new GLTFLoader();
loader.load( 'glass.glb', function ( gltf ) {
  const model =  gltf.scene;
  let num = 0;

  model.traverse((object) => { //モデルの構成要素をforEach的に走査
    if(object.isMesh) { //その構成要素がメッシュだったら

      object.number = num;
      object.material = material.clone();

      // 番号付ける
      num++;
    }
  })

  GlassObject = model;
  GlassObject.scale.set(3.5, 3.5, 3.5);

  scene.add(GlassObject);
  modelSet = true;
})

ガラス片が、バラバラに上から落ちてきて、ループするアニメーションを作成しましょう。

let modelSet = false; //モデルの読み込みが完了したかのフラグ
let GlassObject;

const loader = new GLTFLoader();
loader.load( 'glass.glb', function ( gltf ) {
  const model =  gltf.scene;
  let num = 0;

  model.traverse((object) => { //モデルの構成要素をforEach的に走査
    if(object.isMesh) { //その構成要素がメッシュだったら

      object.number = num;
      object.material = material.clone();
      
      //位置をバラけさせる
      object.position.set(
        (Math.random()-0.5)*3,
        (Math.random()-0.5)*8,
        (Math.random()-0.5)*3
      );
      //回転を加える
      object.rotation.set(
        (Math.random()-0.5)*Math.PI*2,
        (Math.random()-0.5)*Math.PI*2,
        (Math.random()-0.5)*Math.PI*2,
      );
      // 落下のランダムスピードを付ける
      object.speedY = 1.0 + Math.random();
      
      // 番号付ける
      num++;
    }
  })

  GlassObject = model;
  GlassObject.scale.set(3.5, 3.5, 3.5);

  scene.add(GlassObject);
  modelSet = true;
})

AnimationLoop

const clock = new THREE.Clock();

function renderLoop() {
    stats.begin();//stats計測
    const delta = clock.getDelta();//animation programs

    if(modelSet){
      GlassObject.children.forEach((element, index) => {
        // 落下させる
        element.position.y -= element.speedY * delta * 0.2;

       // y軸が-4以下になったら上に再表示させる
        if(element.position.y < -4){
          element.position.x = (Math.random()-0.5)*3;
          element.position.y = 4;
          element.position.z = (Math.random()-0.5)*3;
        }
    // 回転させる
        element.rotation.x += delta * 0.1;
        element.rotation.y += delta * 0.1;
        element.rotation.z += delta * 0.1;
      });
    }

    renderer.render(scene, camera) // render the scene using the camera
    requestAnimationFrame(renderLoop) //loop the render function
    stats.end();//stats計測
}

renderLoop() //start rendering

4.完成!

 簡単でしたね!

【Sample Demo】https://misora.main.jp/glass2/

【MeshPhysicalMaterialパラメータサイト】https://misora.main.jp/physicalm/

【作品サイト】https://misora.main.jp/glass/

作品のサイトでは、scene.backgroundをNoneにして暗い空間に、ガラスのMaterialパラメータでreflectivity=1.0、などにしています。あとPostEffectsのUnrealBloomPassで強調つつ、雰囲気を作りをしました。

これからも、いろいろなところで必須になると思いますので、ぜひ参考にしてみてください。

以上、記事が良かったらXのフォロー、また、もう一つ私の記事をご覧ください。

タイトルとURLをコピーしました