Skip to content

Commit 6c5687c

Browse files
authored
Add glTF support for DRACOLoader and KTX2Loader (#176)
This increases the JS bundle size from 0.93 MiB to 2.03 MiB.
1 parent d9a2319 commit 6c5687c

7 files changed

Lines changed: 351 additions & 1 deletion

dist/main.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ var dat = require('dat.gui').default; // TODO: why is .default needed?
44
import {mergeGeometries} from 'three/examples/jsm/utils/BufferGeometryUtils.js';
55
import {OBJLoader2, MtlObjBridge} from 'wwobjloader2'
66
import {ColladaLoader} from 'three/examples/jsm/loaders/ColladaLoader.js';
7+
import {DRACOLoader} from 'three/examples/jsm/loaders/DRACOLoader.js';
78
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
9+
import {KTX2Loader} from 'three/examples/jsm/loaders/KTX2Loader.js';
810
import {MTLLoader} from 'three/examples/jsm/loaders/MTLLoader.js';
911
import {STLLoader} from 'three/examples/jsm/loaders/STLLoader.js';
1012
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
@@ -13,6 +15,29 @@ import { XRButton } from 'three/examples/jsm/webxr/XRButton.js';
1315
import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerModelFactory';
1416
require('ccapture.js');
1517

18+
// These are bundled as data:// URIs via our webpack.config.js.
19+
const meshcat_inline_assets = {
20+
'basis_transcoder.js': new URL(
21+
'three/examples/jsm/libs/basis/basis_transcoder.js',
22+
import.meta.url).href,
23+
'basis_transcoder.wasm': new URL(
24+
'three/examples/jsm/libs/basis/basis_transcoder.wasm',
25+
import.meta.url).href,
26+
'draco_decoder.wasm': new URL(
27+
'three/examples/jsm/libs/draco/gltf/draco_decoder.wasm',
28+
import.meta.url).href,
29+
'draco_wasm_wrapper.js': new URL(
30+
'three/examples/jsm/libs/draco/gltf/draco_wasm_wrapper.js',
31+
import.meta.url).href,
32+
};
33+
const meshcat_loading_manager = new THREE.LoadingManager();
34+
meshcat_loading_manager.setURLModifier(url => {
35+
if (url in meshcat_inline_assets) {
36+
return meshcat_inline_assets[url];
37+
}
38+
return url;
39+
});
40+
1641
// We implement several MessagePack extension types for arrays, inspired by the
1742
// conventions for msgpack-lite:
1843
// https://github.com/kawanet/msgpack-lite/tree/master#extension-types
@@ -1076,6 +1101,10 @@ class Viewer {
10761101
this.create_camera();
10771102
this.num_messages_received = 0;
10781103

1104+
this.draco_loader = new DRACOLoader(meshcat_loading_manager);
1105+
this.ktx2_loader = new KTX2Loader(meshcat_loading_manager);
1106+
this.ktx2_loader.detectSupport(this.renderer);
1107+
10791108
// TODO: probably shouldn't be directly accessing window?
10801109
window.onload = (evt) => this.set_3d_pane_size();
10811110
window.addEventListener('resize', (evt) => this.set_3d_pane_size(), false);
@@ -1360,6 +1389,8 @@ class Viewer {
13601389
};
13611390
if (object_json.object.type == "_meshfile_object" && object_json.object.format == "gltf") {
13621391
let loader = new GLTFLoader();
1392+
loader.setDRACOLoader(this.draco_loader);
1393+
loader.setKTX2Loader(this.ktx2_loader);
13631394
loader.parse(object_json.object.data, null, (gltf) => {
13641395
let scene = gltf.scene;
13651396
if (scene === null) {

test/Readme.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
# Testing MeshCat
3+
4+
This directory contains various HTML test files that each exercise features of MeshCat. To view the tests, open a local web server:
5+
6+
python3 -m http.server 7000
7+
8+
After running that command, open http://127.0.0.1:7000/ and browse through the index of tests. Use Ctrl-C to exit the server.
9+
10+
Some (but not all) test cases will also work correctly when viewed directly as file:// URLs, but we do not recommend this.
328 Bytes
Binary file not shown.
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset=utf-8>
5+
<title>MeshCat</title>
6+
</head>
7+
<body>
8+
<div id="meshcat-pane">
9+
</div>
10+
11+
<!-- Note for developers: This is the same test as meshfile_object_gltf.html
12+
except that (1) the buffers are no longer embedded inside the glTF file, and
13+
(2) the buffers are optimized using DRACO and KTX2 compression. -->
14+
15+
<script src="../dist/main.min.js"></script>
16+
<script>
17+
var viewer = new MeshCat.Viewer(document.getElementById("meshcat-pane"));
18+
19+
let gltf_contents = `{
20+
"asset": {
21+
"generator": "glTF-Transform v3.10.0",
22+
"version": "2.0"
23+
},
24+
"accessors": [
25+
{
26+
"type": "SCALAR",
27+
"componentType": 5123,
28+
"count": 36
29+
},
30+
{
31+
"type": "VEC3",
32+
"componentType": 5126,
33+
"count": 24,
34+
"max": [
35+
1,
36+
1,
37+
1
38+
],
39+
"min": [
40+
0,
41+
0,
42+
0
43+
]
44+
},
45+
{
46+
"type": "VEC3",
47+
"componentType": 5126,
48+
"count": 24
49+
},
50+
{
51+
"type": "VEC2",
52+
"componentType": 5126,
53+
"count": 24
54+
},
55+
{
56+
"type": "SCALAR",
57+
"componentType": 5123,
58+
"count": 6
59+
},
60+
{
61+
"type": "VEC3",
62+
"componentType": 5126,
63+
"count": 4,
64+
"max": [
65+
1,
66+
1,
67+
0
68+
],
69+
"min": [
70+
-1,
71+
-1,
72+
0
73+
]
74+
},
75+
{
76+
"type": "VEC3",
77+
"componentType": 5126,
78+
"count": 4
79+
}
80+
],
81+
"bufferViews": [
82+
{
83+
"buffer": 0,
84+
"byteOffset": 0,
85+
"byteLength": 213
86+
},
87+
{
88+
"buffer": 0,
89+
"byteOffset": 213,
90+
"byteLength": 115
91+
}
92+
],
93+
"samplers": [
94+
{
95+
"magFilter": 9729,
96+
"minFilter": 9987,
97+
"wrapS": 10497,
98+
"wrapT": 10497
99+
}
100+
],
101+
"textures": [
102+
{
103+
"sampler": 0,
104+
"extensions": {
105+
"KHR_texture_basisu": {
106+
"source": 0
107+
}
108+
}
109+
}
110+
],
111+
"images": [
112+
{
113+
"name": "meshcat_cube",
114+
"mimeType": "image/ktx2",
115+
"uri": "meshfile_object_gltf_optimized.ktx2"
116+
}
117+
],
118+
"buffers": [
119+
{
120+
"uri": "meshfile_object_gltf_optimized.bin",
121+
"byteLength": 328
122+
}
123+
],
124+
"materials": [
125+
{
126+
"name": "Default OBJ",
127+
"doubleSided": true,
128+
"pbrMetallicRoughness": {
129+
"roughnessFactor": 0.06363635510206223,
130+
"baseColorTexture": {
131+
"index": 0
132+
}
133+
},
134+
"extensions": {
135+
"KHR_materials_ior": {
136+
"ior": 1.4500000476837158
137+
},
138+
"KHR_materials_specular": {
139+
"specularColorFactor": [
140+
1.7785181999206543,
141+
1.7785181999206543,
142+
1.7785181999206543
143+
]
144+
}
145+
}
146+
},
147+
{
148+
"name": "PlaneMat",
149+
"doubleSided": true,
150+
"pbrMetallicRoughness": {
151+
"baseColorFactor": [
152+
0.3505544364452362,
153+
0.07363083213567734,
154+
0.07363083213567734,
155+
1
156+
],
157+
"roughnessFactor": 0.5981309413909912,
158+
"metallicFactor": 0.20000000298023224
159+
}
160+
}
161+
],
162+
"meshes": [
163+
{
164+
"name": "meshcat_cube",
165+
"primitives": [
166+
{
167+
"attributes": {
168+
"POSITION": 1,
169+
"NORMAL": 2,
170+
"TEXCOORD_0": 3
171+
},
172+
"mode": 4,
173+
"material": 0,
174+
"indices": 0,
175+
"extensions": {
176+
"KHR_draco_mesh_compression": {
177+
"bufferView": 0,
178+
"attributes": {
179+
"POSITION": 0,
180+
"NORMAL": 1,
181+
"TEXCOORD_0": 2
182+
}
183+
}
184+
}
185+
}
186+
]
187+
},
188+
{
189+
"name": "Plane",
190+
"primitives": [
191+
{
192+
"attributes": {
193+
"POSITION": 5,
194+
"NORMAL": 6
195+
},
196+
"mode": 4,
197+
"material": 1,
198+
"indices": 4,
199+
"extensions": {
200+
"KHR_draco_mesh_compression": {
201+
"bufferView": 1,
202+
"attributes": {
203+
"POSITION": 0,
204+
"NORMAL": 1
205+
}
206+
}
207+
}
208+
}
209+
]
210+
}
211+
],
212+
"nodes": [
213+
{
214+
"name": "meshcat_cube",
215+
"rotation": [
216+
0.43111834797335324,
217+
-0.16214590328170803,
218+
0.28769654695687935,
219+
0.8396882615500162
220+
],
221+
"mesh": 0
222+
},
223+
{
224+
"name": "Plane",
225+
"scale": [
226+
2.1528782844543457,
227+
2.1528782844543457,
228+
2.1528782844543457
229+
],
230+
"mesh": 1
231+
}
232+
],
233+
"scenes": [
234+
{
235+
"name": "Scene",
236+
"nodes": [
237+
0,
238+
1
239+
]
240+
}
241+
],
242+
"scene": 0,
243+
"extensionsUsed": [
244+
"KHR_materials_ior",
245+
"KHR_materials_specular",
246+
"KHR_texture_basisu",
247+
"KHR_draco_mesh_compression"
248+
],
249+
"extensionsRequired": [
250+
"KHR_texture_basisu",
251+
"KHR_draco_mesh_compression"
252+
]
253+
}`;
254+
255+
viewer.handle_command({
256+
type: "set_object",
257+
path: "/meshcat/mesh_test",
258+
object: {
259+
metadata: {version: 4.5, type: "Object"},
260+
geometries: [],
261+
materials: [],
262+
object: {
263+
uuid: "00c2baef-9600-4c6b-b88d-7e82c40e004f",
264+
type: "_meshfile_object",
265+
format: "gltf",
266+
data: gltf_contents
267+
}
268+
}
269+
});
270+
// Enable shadows so we can see the meshes in the gltf cast and receive
271+
// shadows.
272+
viewer.handle_command({
273+
type: "set_property",
274+
path: "/Lights/PointLightNegativeX/<object>",
275+
property: "castShadow",
276+
value: true
277+
});
278+
viewer.handle_command({
279+
type: "set_property",
280+
path: "/Lights/PointLightPositiveX/<object>",
281+
property: "castShadow",
282+
value: true
283+
});
284+
viewer.set_property(["Background", "<object>"], "top_color", [1, 0.25, 0.25]);
285+
viewer.set_property(["Background", "<object>"], "bottom_color", [0.25, 0.25, 1.0]);
286+
</script>
287+
288+
289+
<style>
290+
body {
291+
margin: 0;
292+
}
293+
294+
#meshcat-pane {
295+
width: 100vw;
296+
height: 100vh;
297+
overflow: hidden;
298+
}
299+
</style>
300+
</body>
301+
</html>
1.03 KB
Binary file not shown.

webpack.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ module.exports = [{
1818
},
1919
watch: true,
2020
mode: "production",
21+
module: {
22+
rules: [
23+
{
24+
test: /\/libs\/(basis|draco)\//,
25+
type: 'asset/inline'
26+
}
27+
]
28+
},
2129
plugins: [
2230
new LicensePlugin({
2331
outputFilename: "main.min.js.THIRD_PARTY_LICENSES.json",

0 commit comments

Comments
 (0)