+++
date = "2024-03-19"
tags = ["vrm", "threejs"]
title = "three.jsでbloomを有効にする"
slug = "vrm"
+++

リファクタリングの一環としてweb周りで作ったものを整理しています。

- https://git.syui.ai/ai/vrm

ただ、整理といいつつ、ほとんど新しい実装を試していて、コード自体はきれいになっていません。

以前は、`three-vrm:v0.6`で作成されたプロジェクトのforkを使用していましたが、なかなかに複雑で古いpackageを使用していたので、イチから作り直しました。

`three-vrm:v2.1`にして、`node:v21`, `yarn:v1.22`を使っています。

## bloom

ぼんやりと発光させるには、bloomを有効にしなければなりません。

ただし、threeに入っているexampleはメンテナンスされていません。別のものを使ったほうが良いでしょう。

```sh
$ yarn add postprocessing
```

```js:src/index.ts
//import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
//import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass';
//import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
// https://github.com/pmndrs/postprocessing
import { BloomEffect, EffectComposer, EffectPass, RenderPass } from "postprocessing";

const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
composer.addPass(new EffectPass(camera, new BloomEffect()));

requestAnimationFrame(function render() {

	requestAnimationFrame(render);
	composer.render();

});
```

注意としては、`WebGLRenderer`のoptionによっては動かないことがあるらしいので、そのときは以下を設定してください。

```js:src/index.ts
import { WebGLRenderer } from "three";

const renderer = new WebGLRenderer({
	powerPreference: "high-performance",
	antialias: false,
	stencil: false,
	depth: false
});
```

## progress

progress-barを出します。既に用意されているらしいので、それを使います。

```js:src/index.ts
// https://sbcode.net/threejs/progress-indicator
let manager = new THREE.LoadingManager();
let progressBar = document.getElementById('progressBar') as HTMLProgressElement

// https://threejs.org/docs/#api/en/loaders/managers/LoadingManager
manager.onStart = function ( url, itemsLoaded, itemsTotal ) {
    //console.log( 'Started loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' );
    progressBar.style.display = 'block'
        let percentComplete = (itemsLoaded / itemsTotal) * 100
        progressBar.value = percentComplete === Infinity ? 100 : percentComplete
};
manager.onLoad = function ( ) {
    //console.log( 'Loading complete!');
    progressBar.style.display = 'none'
};
manager.onProgress = function ( url, itemsLoaded, itemsTotal ) {
    let percentComplete = (itemsLoaded / itemsTotal) * 100
        progressBar.value = percentComplete === Infinity ? 100 : percentComplete
        //console.log( 'Loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' );
};
manager.onError = function ( url ) {
    //console.log( 'There was an error loading ' + url );
    progressBar.style.display = 'block'
};
```

```html:dist/index.html
<progress value="0" max="100" id="progressBar"></progress>
```

```css:dist/css/style.css
progress {
	width: 100%;
	height:8px;
	position: absolute;
	border-radius: 0px;
}

::-webkit-progress-bar {
	border-radius: 0px;
	background-color: #e6e6fa;
}

::-webkit-progress-value {
  background-color: #4682b4;
}
```