Skip to content

Commit 2f70677

Browse files
committed
Add bloom effect
Remove unnecessary dependencies
1 parent 1395c9c commit 2f70677

File tree

15 files changed

+85
-31
lines changed

15 files changed

+85
-31
lines changed

assets/i18n/en.json

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"info": "Model Info",
55
"lights": "Toggle Lights",
66
"rotate": "Toggle Auto Rotate",
7+
"bloom": "Toggle Bloom Effect",
78
"hint": "Drop VRM and VMD file to the screen to view them.",
89
"fps": "Frames Per Second",
910
"draw-call": "Draw Calls Per Frame",

assets/i18n/ja.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
"info": "モデル情報",
55
"lights": "照明スイッチ",
66
"rotate": "自動回転スイッチ",
7+
"bloom": "ブルーム効果スイッチ",
78
"hint": "VRM と VMD ファイルを画面にドロップして表示してください。",
8-
"fps": "1秒あたりのフレーム数",
9-
"draw-call": "ドローコール",
9+
"fps": "1秒あたりのフレーム数",
10+
"draw-call": "ドローコール",
1011
"face-count": "三角形数",
1112
"ok": "OK",
1213
"mata_title": "{{title}} の情報",

assets/i18n/zh-cn.json

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"info": "模型信息",
55
"lights": "场景灯光开关",
66
"rotate": "自动旋转开关",
7+
"bloom": "发光效果开关",
78
"hint": "请把 VRM 和 VMD 文件拖曳到画面中间以进行预览。",
89
"fps": "每秒帧数",
910
"draw-call": "绘制指令调用次数 (每帧)",

assets/i18n/zh.json

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"info": "模型資訊",
55
"lights": "場景燈光開關",
66
"rotate": "自動旋轉開關",
7+
"bloom": "發光效果開關",
78
"hint": "請把 VRM 和 VMD 檔拖曳到畫面中間以進行預覽。",
89
"fps": "每秒影格數",
910
"draw-call": "繪製指令呼叫次數 (每影格)",

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
"@types/resize-observer-browser": "latest",
2828
"@types/three": "latest",
2929
"@types/webpack-env": "latest",
30-
"@types/webxr": "^0.2.1",
3130
"dseg": "latest",
3231
"hyperscript": "latest",
3332
"i18next": "latest",

src/global.d.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
declare module "mmd-parser" {
1+
declare module '__global' {
2+
import { Navigator as NavigatorWithXR, Window as WindowWithXR } from 'three';
3+
export {};
4+
global {
5+
// Imports WebXR interface
6+
interface Window extends WindowWithXR {}
7+
interface Navigator extends NavigatorWithXR {}
8+
}
9+
}
10+
11+
declare module 'mmd-parser' {
212
export const CharsetEncoder: any;
313
export class Parser {
414
parsePmd(buffer: ArrayBufferLike, leftToRight?: boolean): any;

src/host/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ export function toggleAutoRotate() {
7575
return void workerService.trigger('toggleRotate');
7676
}
7777

78+
export function toggleBloom() {
79+
return void workerService.trigger('toggleBloom');
80+
}
81+
7882
observeVisibilty.subscribe(
7983
state => workerService.trigger('enable', state === 'visible'),
8084
);

src/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<a class="item" id="info" data-tooltip-lang="info"><i class="notice circle icon"></i></a>
2727
<div class="divider item"></div>
2828
<a class="item" id="lights" data-tooltip-lang="lights"><i class="lightbulb icon"></i></a>
29+
<a class="item" id="bloom" data-tooltip-lang="bloom"><i class="sun icon"></i></a>
2930
<a class="item" id="rotate" data-tooltip-lang="rotate"><i class="repeat icon"></i></a>
3031
</span>
3132
<form class="hidden">

src/main.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import './main.css';
22
import './i18n';
33
import { ajax } from 'rxjs/ajax';
4-
import { canvas, loadAnimation, loadModel, toggleAutoRotate, toggleLights } from './host';
4+
import { canvas, loadAnimation, loadModel, toggleAutoRotate, toggleBloom, toggleLights } from './host';
55
import { setAutoShown, showMoreInfo } from './host/meta-display';
66
import registerStats from './host/status';
77
import { registerDropZone } from './utils/drag-drop';
@@ -95,6 +95,9 @@ if (searchParams.has('dark'))
9595
if (searchParams.has('noinfo'))
9696
setAutoShown(false);
9797

98+
if (searchParams.has('nobloom'))
99+
toggleBloom();
100+
98101
const vrmUrl = searchParams.get('vrm');
99102
if (vrmUrl)
100103
loadingPromises.push((async () => {
@@ -141,6 +144,7 @@ if (searchParams.has('nocontrols'))
141144
workerService.trigger('enableControls', false);
142145

143146
document.querySelector('#lights')?.addEventListener('click', toggleLights);
147+
document.querySelector('#bloom')?.addEventListener('click', toggleBloom);
144148
document.querySelector('#rotate')?.addEventListener('click', toggleAutoRotate);
145149
const fileSelect = document.querySelector<HTMLInputElement>('#selectfile');
146150
document.querySelector('#open')?.addEventListener('click', () => fileSelect?.click());

src/utils/xr-detect.ts

-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
import { Navigator } from 'webxr';
2-
3-
declare var navigator: Navigator;
4-
51
export const isSupported = (async ({ xr }) => {
62
if (!xr) return false;
73
return xr.isSessionSupported('immersive-vr');

src/worker/scene/controls/xr-controls.ts

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
1-
import { Navigator as XRNavigator, XRSession } from 'three';
1+
import { WorkerMessageService } from '../../../utils/message-service';
2+
import { isSupported } from '../../../utils/xr-detect';
3+
import { XRSession } from 'three';
24
import { renderer } from '../renderer';
35
import { isXR } from './common';
46

5-
declare var navigator: Navigator & XRNavigator;
6-
77
let promise: Promise<boolean> | undefined;
88

9-
export const supported = (async ({ xr }) => {
10-
if (!xr) return false;
11-
return xr.isSessionSupported('immersive-vr');
12-
})(navigator);
13-
149
function xrSessionEnd() {
1510
if (!renderer) return;
1611
const xrManager = renderer.xr;
@@ -25,16 +20,15 @@ export function enableXR(enable?: boolean) {
2520

2621
async function execEnableXR(enable?: boolean) {
2722
console.log(navigator);
28-
if (!renderer || !navigator.xr || !await supported) {
29-
console.log('Boo, not supported :(');
23+
if (!renderer || !navigator.xr || !await isSupported) {
24+
WorkerMessageService.host.trigger('warn', 'Failed to initialize webXR.');
3025
return false;
3126
}
3227
const { xr } = navigator;
3328
const xrManager = renderer.xr;
3429
if (enable == null)
3530
enable = !xrManager.enabled;
3631
if (enable && !xrManager.enabled) {
37-
console.log('Trying to enable VR');
3832
let session: XRSession | undefined;
3933
try {
4034
session = await xr.requestSession('immersive-vr', {

src/worker/scene/index.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { Subject } from 'rxjs';
22
import { take } from 'rxjs/operators';
33
import { initWorkerContext, remoteCanvasObservable } from '../../utils/remote-canvas';
44
import { camera } from './camera';
5-
import { scene } from './scene';
65
import { init as initLights } from './lights';
7-
import { init as initRenderer, renderer } from './renderer';
6+
import { init as initRenderer } from './renderer';
7+
import { updateSize, init as initPostProcessing, render } from './post-processing';
88
import { init as initControls, controls, targetPosition, enableOrbit, enableXR } from './controls';
99
import { setCenter } from './floor';
1010
import { WebGLRenderer } from 'three';
@@ -17,8 +17,9 @@ let lastStatsUpdate = 0;
1717
let controlsEnabled = true;
1818

1919
const loopManager = new LoopManager(deltaTime => {
20-
deltaTimeObservable.next(deltaTime / 1000);
21-
renderer?.render(scene, camera);
20+
deltaTime /= 1000;
21+
deltaTimeObservable.next(deltaTime);
22+
render(deltaTime);
2223
frameCount++;
2324
}, true);
2425

@@ -29,14 +30,15 @@ remoteCanvasObservable.pipe(take(1)).subscribe(canvas => {
2930
(self as any).document = {};
3031
const renderer = initRenderer(canvas.undelyOffscreenCanvas);
3132
const controls = initControls(canvas, deltaTimeObservable, true);
33+
initPostProcessing();
3234
handleResize(canvas.width, canvas.height);
3335
deltaTimeObservable.subscribe(() => setCenter(controls.target));
3436
setInterval(notifyRendererStats, 1000, renderer);
3537
});
3638
initWorkerContext();
3739

3840
export function handleResize(width: number, height: number) {
39-
renderer?.setSize(width, height, false);
41+
updateSize(width, height);
4042
camera.aspect = width / height;
4143
camera.updateProjectionMatrix();
4244
}

src/worker/scene/lights.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ scene.background = new Color(bgColor);
88
scene.fog = new Fog(bgColor, 3, 10);
99

1010
let targetIntensity = 1;
11-
let currentIntensity = 0;
11+
export let currentIntensity = 0;
1212
const ambiantLight = new HemisphereLight(0xffffff, 0x444444);
1313
ambiantLight.position.set(0, 20, 0);
1414
scene.add(ambiantLight);

src/worker/scene/post-processing.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Vector2 } from 'three';
2+
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
3+
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';
4+
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass';
5+
import { WorkerMessageService } from '../../utils/message-service';
6+
7+
import { renderer } from './renderer';
8+
import { camera } from './camera';
9+
import { scene } from './scene';
10+
import { currentIntensity } from './lights';
11+
12+
const renderPass = new RenderPass(scene, camera);
13+
let composer: EffectComposer | undefined;
14+
let bloomOn = true;
15+
16+
const bloomPass = new UnrealBloomPass(new Vector2(2048, 2048), 0, 1, 0.3);
17+
18+
export function init() {
19+
if (composer || !renderer) return;
20+
composer = new EffectComposer(renderer);
21+
composer.addPass(renderPass);
22+
composer.addPass(bloomPass);
23+
}
24+
25+
export function updateSize(width: number, height: number) {
26+
renderer?.setSize(width, height, false);
27+
composer?.setSize(width, height);
28+
bloomPass.setSize(width, height);
29+
}
30+
31+
export function render(deltaTime?: number) {
32+
bloomPass.strength = bloomOn ? Math.max(0, 1 - (currentIntensity ** 0.3)) : 0;
33+
composer?.render(deltaTime);
34+
}
35+
36+
export function setBloomEnabled(value: boolean) {
37+
bloomOn = value;
38+
}
39+
40+
export function toggleBloom() {
41+
bloomOn = !bloomOn;
42+
}
43+
44+
45+
WorkerMessageService.host.on({ setBloomEnabled, toggleBloom });

yarn.lock

-5
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,6 @@
219219
"@types/webpack-sources" "*"
220220
source-map "^0.6.0"
221221

222-
"@types/webxr@^0.2.1":
223-
version "0.2.1"
224-
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.2.1.tgz#58eab531ac17d761894cdea63c7d86b3f31cc0d6"
225-
integrity sha512-1WLx0tQUXJKqdIeTPLZPMOzeI+ZdhCdp/iqB8Ke8bWG+tfvSuyWow+MM6Rl/7NGabW1rcwJyO3y3gjnbo2AVvA==
226-
227222
"@webassemblyjs/[email protected]":
228223
version "1.11.0"
229224
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f"

0 commit comments

Comments
 (0)