daydreamer-json commited on
Commit
021c011
·
verified ·
1 Parent(s): 82aaa47
index.html CHANGED
@@ -5,7 +5,7 @@
5
  <meta charset="utf-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
 
8
- <title>Babylon.js sample code</title>
9
 
10
  <!-- Babylon.js -->
11
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
@@ -33,21 +33,18 @@
33
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
34
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap">
35
  <style>
36
- html,
37
- body {
38
  overflow: hidden;
39
  width: 100%;
40
  height: 100%;
41
  margin: 0;
42
  padding: 0;
43
  }
44
-
45
  #renderCanvas {
46
  width: 100%;
47
  height: 100%;
48
  touch-action: none;
49
  }
50
-
51
  #canvasZone {
52
  width: 100%;
53
  height: 100%;
@@ -56,209 +53,6 @@
56
  </head>
57
  <body>
58
  <div id="canvasZone"><canvas id="renderCanvas"></canvas></div>
59
- <script>
60
- const resourcePaths = {
61
- 'mainModel': './res/model/yyb_hatsune_miku_10th_v1.02.bpmx',
62
- 'mainMotion': './res/track/melancholy_night/motion.bvmd',
63
- 'audio': './res/track/melancholy_night/melancholy_night.m4a'
64
- }
65
- var canvas = document.getElementById("renderCanvas");
66
- var startRenderLoop = function (engine, canvas) {
67
- engine.runRenderLoop(function () {
68
- if (sceneToRender && sceneToRender.activeCamera) {
69
- sceneToRender.render();
70
- }
71
- });
72
- };
73
- var engine = null;
74
- var scene = null;
75
- var sceneToRender = null;
76
- var createDefaultEngine = function () {
77
- return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true, disableWebGL2Support: false });
78
- };
79
- class Playground {
80
- static async CreateScene(engine, canvas) {
81
- await new Promise((resolve) => {
82
- const babylonMmdScript = document.createElement("script");
83
- babylonMmdScript.src = "https://www.unpkg.com/babylon-mmd@0.37.2/umd/babylon.mmd.min.js";
84
- document.head.appendChild(babylonMmdScript);
85
- babylonMmdScript.onload = resolve;
86
- });
87
- if (engine.hostInformation.isMobile) {engine.setHardwareScalingLevel(0.85)} else {engine.setHardwareScalingLevel(0.75)};
88
- const pmxLoader = BABYLON.SceneLoader.GetPluginForExtension(".pmx");
89
- const materialBuilder = pmxLoader.materialBuilder;
90
- materialBuilder.useAlphaEvaluation = false;
91
- materialBuilder.loadOutlineRenderingProperties = () => {};
92
- // const alphaBlendMaterials = ["face02", "Facial02", "HL", "Hairshadow", "q302"];
93
- // const alphaTestMaterials = ["q301"];
94
- // materialBuilder.afterBuildSingleMaterial = (material) => {
95
- // if (!alphaBlendMaterials.includes(material.name) && !alphaTestMaterials.includes(material.name)) return;
96
- // material.transparencyMode = alphaBlendMaterials.includes(material.name) ? BABYLON.Material.MATERIAL_ALPHABLEND : BABYLON.Material.MATERIAL_ALPHATEST;
97
- // material.useAlphaFromDiffuseTexture = true;
98
- // material.diffuseTexture.hasAlpha = true;
99
- // };
100
- const scene = new BABYLON.Scene(engine);
101
- // BABYLON.SceneOptimizer.OptimizeAsync(scene);
102
- // scene.clearColor = new BABYLON.Color4(0.95, 0.95, 0.95, 1.0);
103
- scene.clearColor = new BABYLON.Color4(0, 0, 0, 1.0);
104
- const mmdCamera = new BABYLONMMD.MmdCamera("MmdCamera", new BABYLON.Vector3(0, 10, 0), scene);
105
- mmdCamera.maxZ = 5000;
106
- const camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 0, 0, 45, new BABYLON.Vector3(0, 10, 0), scene);
107
- camera.maxZ = 5000;
108
- camera.setPosition(new BABYLON.Vector3(0, 10, -45));
109
- camera.attachControl(canvas, false);
110
- camera.inertia = 0.8;
111
- camera.speed = 10;
112
- const hemisphericLight = new BABYLON.HemisphericLight("HemisphericLight", new BABYLON.Vector3(0, 1, 0), scene);
113
- hemisphericLight.intensity = 0.4;
114
- hemisphericLight.specular = new BABYLON.Color3(0, 0, 0);
115
- hemisphericLight.groundColor = new BABYLON.Color3(1, 0.9, 0.9);
116
- const directionalLight = new BABYLON.DirectionalLight("DirectionalLight", new BABYLON.Vector3(0.5, -1, 1), scene);
117
- directionalLight.intensity = 0.8;
118
- directionalLight.autoCalcShadowZBounds = false;
119
- directionalLight.autoUpdateExtends = false;
120
- directionalLight.shadowMaxZ = 20;
121
- directionalLight.shadowMinZ = -15;
122
- directionalLight.orthoTop = 18;
123
- directionalLight.orthoBottom = -1;
124
- directionalLight.orthoLeft = -10;
125
- directionalLight.orthoRight = 10;
126
- directionalLight.shadowOrthoScale = 0;
127
- const shadowGenerator = new BABYLON.ShadowGenerator(1024, directionalLight, true);
128
- shadowGenerator.usePercentageCloserFiltering = true;
129
- shadowGenerator.forceBackFacesOnly = true;
130
- shadowGenerator.filteringQuality = BABYLON.ShadowGenerator.QUALITY_MEDIUM;
131
- shadowGenerator.frustumEdgeFalloff = 0.1;
132
- const mmdRuntime = new BABYLONMMD.MmdRuntime(scene, new BABYLONMMD.MmdPhysics(scene));
133
- mmdRuntime.register(scene);
134
- const audioPlayer = new BABYLONMMD.StreamAudioPlayer(scene);
135
- audioPlayer.preservesPitch = false;
136
- audioPlayer.source = resourcePaths.audio;
137
- mmdRuntime.setAudioPlayer(audioPlayer);
138
- const mmdPlayerControl = new BABYLONMMD.MmdPlayerControl(scene, mmdRuntime, audioPlayer);
139
- mmdPlayerControl.showPlayerControl();
140
- engine.displayLoadingUI();
141
- let loadingTexts = [];
142
- const updateLoadingText = (updateIndex, text) => {
143
- loadingTexts[updateIndex] = text;
144
- engine.loadingUIText = "<br/><br/><br/><br/>" + loadingTexts.join("<br/><br/>");
145
- };
146
- const promises = [];
147
- const bvmdLoader = new BABYLONMMD.BvmdLoader(scene);
148
- promises.push(bvmdLoader.loadAsync("motion", resourcePaths.mainMotion, (event) => updateLoadingText(0, `Loading motion... ${event.loaded}/${event.total} (${Math.floor((event.loaded * 100) / event.total)}%)`)));
149
- promises.push(BABYLON.SceneLoader.ImportMeshAsync(undefined, resourcePaths.mainModel, undefined, scene, (event) => updateLoadingText(1, `Loading model... ${event.loaded}/${event.total} (${Math.floor((event.loaded * 100) / event.total)}%)`)));
150
- promises.push(
151
- (async () => {
152
- updateLoadingText(2, "Loading physics engine...");
153
- const havokPlugin = new BABYLON.HavokPlugin();
154
- // scene.enablePhysics(new BABYLON.Vector3(0, -9.8, 0), havokPlugin);
155
- scene.enablePhysics(new BABYLON.Vector3(0, -1, 0), havokPlugin);
156
- updateLoadingText(2, "Loading physics engine... Done");
157
- })()
158
- );
159
- loadingTexts = new Array(promises.length).fill("");
160
- const loadResults = await Promise.all(promises);
161
- scene.onAfterRenderObservable.addOnce(() => engine.hideLoadingUI());
162
- mmdRuntime.setCamera(mmdCamera);
163
- mmdCamera.addAnimation(loadResults[0]);
164
- mmdCamera.setAnimation("motion");
165
- const modelMesh = loadResults[1].meshes[0];
166
- modelMesh.receiveShadows = true;
167
- shadowGenerator.addShadowCaster(modelMesh);
168
- const mmdModel = mmdRuntime.createMmdModel(modelMesh);
169
- mmdModel.addAnimation(loadResults[0]);
170
- mmdModel.setAnimation("motion");
171
- const bodyBone = loadResults[1].skeletons[0].bones.find((bone) => bone.name === "センター");
172
- scene.onBeforeRenderObservable.add(() => {
173
- bodyBone.getFinalMatrix().getTranslationToRef(directionalLight.position);
174
- directionalLight.position.y -= 10;
175
- });
176
- const ground = BABYLON.MeshBuilder.CreateGround("Ground", { width: 100, height: 100, subdivisions: 2, updatable: false }, scene);
177
- ground.receiveShadows = true;
178
- const groundMaterial = (ground.material = new BABYLON.StandardMaterial("GroundMaterial", scene));
179
- groundMaterial.diffuseColor = new BABYLON.Color3(0.25, 0.25, 0.25);
180
- groundMaterial.specularPower = 128;
181
- const groundReflectionTexture = (groundMaterial.reflectionTexture = new BABYLON.MirrorTexture("MirrorTexture", 1024, scene, true));
182
- groundReflectionTexture.mirrorPlane = BABYLON.Plane.FromPositionAndNormal(ground.position, ground.getFacetNormal(0).scale(-1));
183
- groundReflectionTexture.renderList = [modelMesh];
184
- groundReflectionTexture.level = 0.45;
185
- const defaultPipeline = new BABYLON.DefaultRenderingPipeline("default", true, scene, [mmdCamera, camera]);
186
- defaultPipeline.samples = 4;
187
- defaultPipeline.bloomEnabled = true;
188
- defaultPipeline.chromaticAberrationEnabled = true;
189
- defaultPipeline.chromaticAberration.aberrationAmount = 1;
190
- defaultPipeline.fxaaEnabled = true;
191
- defaultPipeline.imageProcessingEnabled = true;
192
- defaultPipeline.imageProcessing.toneMappingEnabled = false;
193
- defaultPipeline.imageProcessing.toneMappingType = BABYLON.ImageProcessingConfiguration.TONEMAPPING_ACES;
194
- defaultPipeline.imageProcessing.vignetteWeight = 0.5;
195
- defaultPipeline.imageProcessing.vignetteStretch = 0.5;
196
- defaultPipeline.imageProcessing.vignetteColor = new BABYLON.Color4(0, 0, 0, 0);
197
- defaultPipeline.imageProcessing.vignetteEnabled = true;
198
- const guiCamera = new BABYLON.ArcRotateCamera("GUICamera", Math.PI / 2 + Math.PI / 7, Math.PI / 2, 100, new BABYLON.Vector3(0, 20, 0), scene);
199
- guiCamera.layerMask = 0x10000000;
200
- scene.activeCameras = [mmdCamera, guiCamera];
201
- let lastClickTime = -Infinity;
202
- canvas.onclick = () => {
203
- const currentTime = performance.now();
204
- if (500 < currentTime - lastClickTime) {
205
- lastClickTime = currentTime;
206
- return;
207
- }
208
- lastClickTime = -Infinity;
209
- if (scene.activeCameras[0] === mmdCamera) scene.activeCameras = [camera, guiCamera];
210
- else scene.activeCameras = [mmdCamera, guiCamera];
211
- };
212
- const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
213
- advancedTexture.layer.layerMask = 0x10000000;
214
- advancedTexture.renderScale = 1.5;
215
- const textblock = new BABYLON.GUI.TextBlock();
216
- // textblock.widthInPixels = 800;
217
- // textblock.left = 10;
218
- textblock.text = `${engine._glRenderer}\n${engine._glVersion}`;
219
- textblock.fontSize = 32;
220
- textblock.fontFamily = "system-ui";
221
- textblock.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
222
- textblock.textVerticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
223
- textblock.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
224
- textblock.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
225
- textblock.color = "#ffffff";
226
- advancedTexture.addControl(textblock);
227
- const textBlockUpdateDisp = setInterval(() => {textblock.text = `${engine._glRenderer}\n${engine._glVersion}\n\n${engine.frameId} frame\n${Math.floor(engine.getFps())} fps\n${Math.floor(engine.performanceMonitor.averageFrameTime)} ms`;}, 10);
228
- mmdRuntime.playAnimation();
229
- return scene;
230
- }
231
- }
232
- createScene = function () {
233
- return Playground.CreateScene(engine, engine.getRenderingCanvas());
234
- };
235
- window.initFunction = async function () {
236
- globalThis.HK = await HavokPhysics();
237
-
238
- var asyncEngineCreation = async function () {
239
- try {
240
- return createDefaultEngine();
241
- } catch (e) {
242
- console.log("the available createEngine function failed. Creating the default engine instead");
243
- return createDefaultEngine();
244
- }
245
- };
246
-
247
- window.engine = await asyncEngineCreation();
248
- if (!engine) throw "engine should not be null.";
249
- startRenderLoop(engine, canvas);
250
- window.scene = createScene();
251
- };
252
- initFunction().then(() => {
253
- scene.then((returnedScene) => {
254
- sceneToRender = returnedScene;
255
- });
256
- });
257
-
258
- // Resize
259
- window.addEventListener("resize", function () {
260
- engine.resize();
261
- });
262
- </script>
263
  </body>
264
  </html>
 
5
  <meta charset="utf-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
 
8
+ <title>Babylon.js MMD Test</title>
9
 
10
  <!-- Babylon.js -->
11
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
 
33
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
34
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap">
35
  <style>
36
+ html, body {
 
37
  overflow: hidden;
38
  width: 100%;
39
  height: 100%;
40
  margin: 0;
41
  padding: 0;
42
  }
 
43
  #renderCanvas {
44
  width: 100%;
45
  height: 100%;
46
  touch-action: none;
47
  }
 
48
  #canvasZone {
49
  width: 100%;
50
  height: 100%;
 
53
  </head>
54
  <body>
55
  <div id="canvasZone"><canvas id="renderCanvas"></canvas></div>
56
+ <script src="script.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  </body>
58
  </html>
res/model/Alicia.bpmx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:33062a79d4f338610c77924598bbbd38c4cd17d1f204a277591e4e0e5dde96c6
3
+ size 8109215
res/model/Alicia/Alicia_blade.pmx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:90fe040b70cead1f0c73d9c304f6d61f5c1e8189a2643e88b9170b435b9c77d5
3
+ size 319682
res/model/Alicia/Alicia_body.png ADDED

Git LFS Details

  • SHA256: c270a0ce8465f5264af209132e7a2417af897b63c8e49ae541bccad955403d97
  • Pointer size: 131 Bytes
  • Size of remote file: 530 kB
res/model/Alicia/Alicia_eye.png ADDED

Git LFS Details

  • SHA256: aafac9f1e664d2718b64a8eec22d5a5b0f2197907d26b0b21d3dbbe49bbfa6d9
  • Pointer size: 131 Bytes
  • Size of remote file: 179 kB
res/model/Alicia/Alicia_face.png ADDED

Git LFS Details

  • SHA256: e483e694109d437e0bff5718d20a905a7d40fac3cefa9bb457bb4ce6aee68a6d
  • Pointer size: 131 Bytes
  • Size of remote file: 514 kB
res/model/Alicia/Alicia_hair.png ADDED

Git LFS Details

  • SHA256: 2116eb48af8e2c9ff1c065633ba39dc92dfa35cbe3e6454054a55427362272ab
  • Pointer size: 131 Bytes
  • Size of remote file: 712 kB
res/model/Alicia/Alicia_other.png ADDED

Git LFS Details

  • SHA256: b5fcda8db5709e73fe6935f27e59fb0c69feba22221545260758ef980f683841
  • Pointer size: 131 Bytes
  • Size of remote file: 333 kB
res/model/Alicia/Alicia_rod.png ADDED

Git LFS Details

  • SHA256: e7b90ad145880701abf5dfbf97c3321dcf37783368068a8f0e786cff56f5c65f
  • Pointer size: 131 Bytes
  • Size of remote file: 473 kB
res/model/Alicia/Alicia_solid.pmx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:62f04b066f0d2a28fb09126bc82d94fa24c0d8f2cd8d7e78b5a0a2d3989d280b
3
+ size 1482421
res/model/Alicia/Alicia_wear.png ADDED

Git LFS Details

  • SHA256: 5a77cca424c2338d8d78135c00726247a423025fe7f27662f86dd48f2efbf406
  • Pointer size: 132 Bytes
  • Size of remote file: 2.62 MB
res/model/Alicia/blade_s.bmp ADDED

Git LFS Details

  • SHA256: 1c5598f0c1c15b4b14645e8d9a5126bdcbfc9a7456f67d8908cee42c05de5df0
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/model/Alicia/eye_s.bmp ADDED

Git LFS Details

  • SHA256: ce397a04d8327cb88b0c5d4c85c523c1e7fc788ac8ec22a561f8c50b78888d94
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/model/Alicia/face_s.bmp ADDED

Git LFS Details

  • SHA256: 6b508c18135ad5c2e14b8df7faa480e7f83c74487f247d35c7669118538582f6
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/model/Alicia/hair_s.bmp ADDED

Git LFS Details

  • SHA256: 3714e1815680265a21f5d1ae4d114bda4dbf8e99e39755d3f0cd1fc3cc1066f5
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/model/Alicia/ramp_s.bmp ADDED

Git LFS Details

  • SHA256: 3dd161d7f3bce407b58ab8fb998295109ed52cf9695008c7cf4c1d3dba77ed19
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/model/Alicia/rod_s.bmp ADDED

Git LFS Details

  • SHA256: 9f3eae57f42cb13d5b5175729acde386fa3238a0100ed7125f1fae5e25351760
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/model/Alicia/shoes_s.bmp ADDED

Git LFS Details

  • SHA256: e2f34da0d8268317de947f9bd4e2bad241d3f26dd867f5737f822509f79ae7b6
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/model/Alicia/skin_s.bmp ADDED

Git LFS Details

  • SHA256: 3714e1815680265a21f5d1ae4d114bda4dbf8e99e39755d3f0cd1fc3cc1066f5
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/model/Alicia/tongue_s.bmp ADDED

Git LFS Details

  • SHA256: d9e725ae7119c387a1b48662af1c1602d462bfea8820a57d8c3bd1eafe2d5bd6
  • Pointer size: 131 Bytes
  • Size of remote file: 197 kB
res/track/conqueror/merged.bvmd ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c768d7723c2b7f5e2c07da63d802bd13f763a98fdde6479069831dfe5e11ef13
3
+ size 3738836
script.js ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const mathFunc = {
2
+ 'arrayMax': (array) => {
3
+ const maxfct = (a, b) => {return Math.max(a, b)};
4
+ return array.reduce(maxfct);
5
+ },
6
+ 'arrayMin': (array) => {
7
+ const minfct = (a, b) => {return Math.min(a, b)};
8
+ return array.reduce(minfct);
9
+ },
10
+ 'arrayTotal': (array) => {
11
+ return array.reduce((acc, f) => acc + f, 0);
12
+ },
13
+ 'arrayAvg': (array) => {
14
+ return array.reduce((acc, f) => acc + f, 0) / array.length;
15
+ },
16
+ 'rounder': (method, num, n, zeroPadding = false) => {
17
+ const pow = Math.pow(10, n);
18
+ let result;
19
+ switch (method) {
20
+ case 'floor':
21
+ result = Math.floor(num * pow) / pow;
22
+ break;
23
+ case 'ceil':
24
+ result = Math.ceil(num * pow) / pow;
25
+ break;
26
+ case 'round':
27
+ result = Math.round(num * pow) / pow;
28
+ break;
29
+ default:
30
+ throw new Error('Invalid rounding method specified.');
31
+ }
32
+ if (zeroPadding) {
33
+ return result.toFixed(n);
34
+ } else {
35
+ return result;
36
+ }
37
+ },
38
+ 'formatFileSize': (bytes, decimals = 2) => {
39
+ if (bytes === 0) return '0 byte';
40
+ const k = 1024;
41
+ const dm = decimals < 0 ? 0 : decimals;
42
+ const sizes = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
43
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
44
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
45
+ }
46
+ };
47
+
48
+ const resourcePathSetsDefault = {
49
+ 'track': 'melancholy_night',
50
+ 'mainModel': 'alicia'
51
+ };
52
+ const resourcePathSets = {
53
+ 'track': {
54
+ 'conqueror': {
55
+ 'mainMotion': './res/track/conqueror/merged.bvmd',
56
+ 'audio': './res/track/conqueror/audio.m4a'
57
+ },
58
+ 'melancholy_night': {
59
+ 'mainMotion': './res/track/melancholy_night/motion.bvmd',
60
+ 'audio': './res/track/melancholy_night/melancholy_night.m4a'
61
+ }
62
+ },
63
+ 'mainModel': {
64
+ 'alicia': './res/model/Alicia.bpmx',
65
+ 'raidenShogun': './res/model/RaidenShogun.bpmx',
66
+ 'yyb_miku_10th': './res/model/yyb_hatsune_miku_10th_v1.02.bpmx'
67
+ }
68
+ };
69
+ const resourcePaths = {
70
+ 'mainModel': resourcePathSets.mainModel[resourcePathSetsDefault.mainModel],
71
+ 'mainMotion': resourcePathSets.track[resourcePathSetsDefault.track].mainMotion,
72
+ 'audio': resourcePathSets.track[resourcePathSetsDefault.track].audio,
73
+ };
74
+ const urlQueryObject = Object.fromEntries(new URLSearchParams(window.location.search));
75
+ if (Object.keys(urlQueryObject).some(el => el === 'track')) {
76
+ for (let i = 0; i < Object.keys(resourcePathSets.track).length; i++) {
77
+ if (urlQueryObject.track === Object.keys(resourcePathSets.track)[i]) {
78
+ resourcePaths.mainMotion = resourcePathSets.track[Object.keys(resourcePathSets.track)[i]].mainMotion;
79
+ resourcePaths.audio = resourcePathSets.track[Object.keys(resourcePathSets.track)[i]].audio;
80
+ }
81
+ }
82
+ }
83
+ if (Object.keys(urlQueryObject).some(el => el === 'mainModel')) {
84
+ for (let i = 0; i < Object.keys(resourcePathSets.mainModel).length; i++) {
85
+ if (urlQueryObject.mainModel === Object.keys(resourcePathSets.mainModel)[i]) {
86
+ resourcePaths.mainModel = resourcePathSets.mainModel[Object.keys(resourcePathSets.mainModel)[i]];
87
+ }
88
+ }
89
+ }
90
+
91
+ var canvas = document.getElementById("renderCanvas");
92
+ var startRenderLoop = function (engine, canvas) {
93
+ engine.runRenderLoop(function () {
94
+ if (sceneToRender && sceneToRender.activeCamera) {
95
+ sceneToRender.render();
96
+ }
97
+ });
98
+ };
99
+ var engine = null;
100
+ var scene = null;
101
+ var sceneToRender = null;
102
+ var createDefaultEngine = function () {
103
+ return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true, disableWebGL2Support: false });
104
+ };
105
+ class Playground {
106
+ static async CreateScene(engine, canvas) {
107
+ await new Promise((resolve) => {
108
+ const babylonMmdScript = document.createElement("script");
109
+ babylonMmdScript.src = "https://www.unpkg.com/babylon-mmd@0.37.2/umd/babylon.mmd.min.js";
110
+ document.head.appendChild(babylonMmdScript);
111
+ babylonMmdScript.onload = resolve;
112
+ });
113
+ if (engine.hostInformation.isMobile) {engine.setHardwareScalingLevel(0.85)} else {engine.setHardwareScalingLevel(0.75)}
114
+ const pmxLoader = BABYLON.SceneLoader.GetPluginForExtension(".pmx");
115
+ const materialBuilder = pmxLoader.materialBuilder;
116
+ materialBuilder.useAlphaEvaluation = false;
117
+ materialBuilder.loadOutlineRenderingProperties = () => {};
118
+ // const alphaBlendMaterials = ["face02", "Facial02", "HL", "Hairshadow", "q302"];
119
+ // const alphaTestMaterials = ["q301"];
120
+ // materialBuilder.afterBuildSingleMaterial = (material) => {
121
+ // if (!alphaBlendMaterials.includes(material.name) && !alphaTestMaterials.includes(material.name)) return;
122
+ // material.transparencyMode = alphaBlendMaterials.includes(material.name) ? BABYLON.Material.MATERIAL_ALPHABLEND : BABYLON.Material.MATERIAL_ALPHATEST;
123
+ // material.useAlphaFromDiffuseTexture = true;
124
+ // material.diffuseTexture.hasAlpha = true;
125
+ // };
126
+ const scene = new BABYLON.Scene(engine);
127
+ // BABYLON.SceneOptimizer.OptimizeAsync(scene);
128
+ // scene.clearColor = new BABYLON.Color4(0.95, 0.95, 0.95, 1.0);
129
+ scene.clearColor = new BABYLON.Color4(0, 0, 0, 1.0);
130
+ const mmdCamera = new BABYLONMMD.MmdCamera("MmdCamera", new BABYLON.Vector3(0, 10, 0), scene);
131
+ mmdCamera.maxZ = 5000;
132
+ const camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 0, 0, 45, new BABYLON.Vector3(0, 10, 0), scene);
133
+ camera.maxZ = 5000;
134
+ camera.setPosition(new BABYLON.Vector3(0, 10, -45));
135
+ camera.attachControl(canvas, false);
136
+ camera.inertia = 0.8;
137
+ camera.speed = 10;
138
+ const hemisphericLight = new BABYLON.HemisphericLight("HemisphericLight", new BABYLON.Vector3(0, 1, 0), scene);
139
+ hemisphericLight.intensity = 0.4;
140
+ hemisphericLight.specular = new BABYLON.Color3(0, 0, 0);
141
+ hemisphericLight.groundColor = new BABYLON.Color3(1, 0.9, 0.9);
142
+ const directionalLight = new BABYLON.DirectionalLight("DirectionalLight", new BABYLON.Vector3(0.5, -1, 1), scene);
143
+ directionalLight.intensity = 0.8;
144
+ directionalLight.autoCalcShadowZBounds = false;
145
+ directionalLight.autoUpdateExtends = false;
146
+ directionalLight.shadowMaxZ = 20;
147
+ directionalLight.shadowMinZ = -15;
148
+ directionalLight.orthoTop = 18;
149
+ directionalLight.orthoBottom = -1;
150
+ directionalLight.orthoLeft = -10;
151
+ directionalLight.orthoRight = 10;
152
+ directionalLight.shadowOrthoScale = 0;
153
+ const shadowGenerator = new BABYLON.ShadowGenerator(1024, directionalLight, true);
154
+ shadowGenerator.usePercentageCloserFiltering = true;
155
+ shadowGenerator.forceBackFacesOnly = true;
156
+ shadowGenerator.filteringQuality = BABYLON.ShadowGenerator.QUALITY_MEDIUM;
157
+ shadowGenerator.frustumEdgeFalloff = 0.1;
158
+ const mmdRuntime = new BABYLONMMD.MmdRuntime(scene, new BABYLONMMD.MmdPhysics(scene));
159
+ mmdRuntime.register(scene);
160
+ const audioPlayer = new BABYLONMMD.StreamAudioPlayer(scene);
161
+ audioPlayer.preservesPitch = false;
162
+ audioPlayer.source = resourcePaths.audio;
163
+ mmdRuntime.setAudioPlayer(audioPlayer);
164
+ const mmdPlayerControl = new BABYLONMMD.MmdPlayerControl(scene, mmdRuntime, audioPlayer);
165
+ mmdPlayerControl.showPlayerControl();
166
+ engine.displayLoadingUI();
167
+ let loadingTexts = [];
168
+ const updateLoadingText = (updateIndex, text) => {
169
+ loadingTexts[updateIndex] = text;
170
+ engine.loadingUIText = "<br/><br/><br/><br/>" + loadingTexts.join("<br/><br/>");
171
+ };
172
+ const promises = [];
173
+ const bvmdLoader = new BABYLONMMD.BvmdLoader(scene);
174
+ promises.push(bvmdLoader.loadAsync("motion", resourcePaths.mainMotion, (event) => updateLoadingText(0, `Loading motion... ${event.loaded}/${event.total} (${Math.floor((event.loaded * 100) / event.total)}%)`)));
175
+ promises.push(BABYLON.SceneLoader.ImportMeshAsync(undefined, resourcePaths.mainModel, undefined, scene, (event) => updateLoadingText(1, `Loading model... ${event.loaded}/${event.total} (${Math.floor((event.loaded * 100) / event.total)}%)`)));
176
+ promises.push(
177
+ (async () => {
178
+ updateLoadingText(2, "Loading physics engine...");
179
+ const havokPlugin = new BABYLON.HavokPlugin();
180
+ // scene.enablePhysics(new BABYLON.Vector3(0, -9.8, 0), havokPlugin);
181
+ scene.enablePhysics(new BABYLON.Vector3(0, -9.8, 0), havokPlugin);
182
+ updateLoadingText(2, "Loading physics engine... Done");
183
+ })()
184
+ );
185
+ loadingTexts = new Array(promises.length).fill("");
186
+ const loadResults = await Promise.all(promises);
187
+ scene.onAfterRenderObservable.addOnce(() => engine.hideLoadingUI());
188
+ mmdRuntime.setCamera(mmdCamera);
189
+ mmdCamera.addAnimation(loadResults[0]);
190
+ mmdCamera.setAnimation("motion");
191
+ const modelMesh = loadResults[1].meshes[0];
192
+ modelMesh.receiveShadows = true;
193
+ shadowGenerator.addShadowCaster(modelMesh);
194
+ const mmdModel = mmdRuntime.createMmdModel(modelMesh);
195
+ mmdModel.addAnimation(loadResults[0]);
196
+ mmdModel.setAnimation("motion");
197
+ mmdModel.mesh.edgesColor = new BABYLON.Color4(0.152, 0.062, 0.035, 1.0);
198
+ mmdModel.mesh.edgesWidth = 100;
199
+ const bodyBone = loadResults[1].skeletons[0].bones.find((bone) => bone.name === "センター");
200
+ scene.onBeforeRenderObservable.add(() => {
201
+ bodyBone.getFinalMatrix().getTranslationToRef(directionalLight.position);
202
+ directionalLight.position.y -= 10;
203
+ });
204
+ const ground = BABYLON.MeshBuilder.CreateGround("Ground", { width: 100, height: 100, subdivisions: 2, updatable: false }, scene);
205
+ ground.receiveShadows = true;
206
+ const groundMaterial = (ground.material = new BABYLON.StandardMaterial("GroundMaterial", scene));
207
+ groundMaterial.diffuseColor = new BABYLON.Color3(0.25, 0.25, 0.25);
208
+ groundMaterial.specularPower = 128;
209
+ const groundReflectionTexture = (groundMaterial.reflectionTexture = new BABYLON.MirrorTexture("MirrorTexture", 1024, scene, true));
210
+ groundReflectionTexture.mirrorPlane = BABYLON.Plane.FromPositionAndNormal(ground.position, ground.getFacetNormal(0).scale(-1));
211
+ groundReflectionTexture.renderList = [modelMesh];
212
+ groundReflectionTexture.level = 0.25;
213
+ const defaultPipeline = new BABYLON.DefaultRenderingPipeline("default", true, scene, [mmdCamera, camera]);
214
+ defaultPipeline.samples = 4;
215
+ defaultPipeline.bloomEnabled = true;
216
+ defaultPipeline.bloomThreshold = 0;
217
+ defaultPipeline.bloomWeight = 0.1;
218
+ defaultPipeline.bloomKernel = 38;
219
+ defaultPipeline.bloomScale = 0.5;
220
+ defaultPipeline.chromaticAberrationEnabled = true;
221
+ defaultPipeline.chromaticAberration.aberrationAmount = 0;
222
+ defaultPipeline.fxaaEnabled = true;
223
+ defaultPipeline.imageProcessingEnabled = true;
224
+ defaultPipeline.imageProcessing.toneMappingEnabled = false;
225
+ defaultPipeline.imageProcessing.toneMappingType = BABYLON.ImageProcessingConfiguration.TONEMAPPING_ACES;
226
+ defaultPipeline.imageProcessing.vignetteWeight = 0.5;
227
+ defaultPipeline.imageProcessing.vignetteStretch = 0.5;
228
+ defaultPipeline.imageProcessing.vignetteColor = new BABYLON.Color4(0, 0, 0, 0);
229
+ defaultPipeline.imageProcessing.vignetteEnabled = true;
230
+ const lensEffect = new BABYLON.LensRenderingPipeline('lensEffects', {edge_blur: engine.hostInformation.isMobile ? 0.0 : 1.0, chromatic_aberration: 1.0, distortion: 0.125}, scene, 1.0);
231
+ scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline('lensEffects', camera);
232
+ scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline('lensEffects', mmdCamera);
233
+ // BABYLON.ParticleHelper.CreateAsync("rain", scene, false).then((set) => {set.start()});
234
+ const guiCamera = new BABYLON.ArcRotateCamera("GUICamera", Math.PI / 2 + Math.PI / 7, Math.PI / 2, 100, new BABYLON.Vector3(0, 20, 0), scene);
235
+ guiCamera.layerMask = 0x10000000;
236
+ scene.activeCameras = [mmdCamera, guiCamera];
237
+ let lastClickTime = -Infinity;
238
+ canvas.onclick = () => {
239
+ const currentTime = performance.now();
240
+ if (500 < currentTime - lastClickTime) {
241
+ lastClickTime = currentTime;
242
+ return;
243
+ }
244
+ lastClickTime = -Infinity;
245
+ if (scene.activeCameras[0] === mmdCamera) scene.activeCameras = [camera, guiCamera];
246
+ else scene.activeCameras = [mmdCamera, guiCamera];
247
+ };
248
+ const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
249
+ advancedTexture.layer.layerMask = 0x10000000;
250
+ advancedTexture.renderScale = 1.5;
251
+ const textblock = new BABYLON.GUI.TextBlock();
252
+ // textblock.widthInPixels = 800;
253
+ // textblock.left = 10;
254
+ textblock.text = `${engine._glRenderer}\n${engine._glVersion}`;
255
+ textblock.fontSize = 32;
256
+ textblock.fontFamily = "system-ui";
257
+ textblock.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
258
+ textblock.textVerticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
259
+ textblock.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
260
+ textblock.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
261
+ textblock.color = "#ffffff";
262
+ advancedTexture.addControl(textblock);
263
+ const textBlockUpdateDisp = setInterval(() => {
264
+ if (engine.hostInformation.isMobile) {
265
+ textblock.text = `${engine._glRenderer}\n${engine._glVersion}\n\n${engine.frameId} f\n${mathFunc.rounder('floor', engine.getFps(), 2)} fps\n${mathFunc.rounder('floor', engine.performanceMonitor.averageFrameTime, 2)} ms`;
266
+ } else {
267
+ textblock.text = `${engine._glRenderer}\n${engine._glVersion}\n\n${resourcePaths.mainModel}\n${resourcePaths.mainMotion}\n${resourcePaths.audio}\n\n${engine.frameId} frame\n${Math.floor(engine.getFps())} fps\n${Math.floor(engine.performanceMonitor.averageFrameTime)} ms`;
268
+ }
269
+ }, 10);
270
+ await new Promise(resolve => setTimeout(resolve, 1000));
271
+ mmdRuntime.playAnimation();
272
+ return scene;
273
+ }
274
+ }
275
+ createScene = function () {
276
+ return Playground.CreateScene(engine, engine.getRenderingCanvas());
277
+ };
278
+ window.initFunction = async function () {
279
+ globalThis.HK = await HavokPhysics();
280
+
281
+ var asyncEngineCreation = async function () {
282
+ try {
283
+ return createDefaultEngine();
284
+ } catch (e) {
285
+ console.log("the available createEngine function failed. Creating the default engine instead");
286
+ return createDefaultEngine();
287
+ }
288
+ };
289
+
290
+ window.engine = await asyncEngineCreation();
291
+ if (!engine) throw "engine should not be null.";
292
+ startRenderLoop(engine, canvas);
293
+ window.scene = createScene();
294
+ };
295
+ initFunction().then(() => {
296
+ scene.then((returnedScene) => {
297
+ sceneToRender = returnedScene;
298
+ });
299
+ });
300
+
301
+ // Resize
302
+ window.addEventListener("resize", function () {
303
+ engine.resize();
304
+ });