lunchboxjs 0.1.4002 → 0.1.4006-dev002
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/lunchboxjs.js +177 -49
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +173 -49
- package/package.json +3 -1
- package/src/components/LunchboxWrapper/LunchboxWrapper.ts +52 -9
- package/src/components/LunchboxWrapper/resizeCanvas.ts +12 -4
- package/src/components/autoGeneratedComponents.ts +175 -0
- package/src/components/index.ts +5 -188
- package/src/core/ensure.ts +27 -5
- package/src/core/interaction/index.ts +1 -0
- package/src/core/update.ts +27 -9
- package/src/index.ts +56 -8
- package/src/types.ts +10 -0
|
@@ -9,27 +9,36 @@ const allNodes = [];
|
|
|
9
9
|
const resizeCanvas = (width, height) => {
|
|
10
10
|
const renderer = ensureRenderer.value?.instance;
|
|
11
11
|
const scene = ensuredScene.value.instance;
|
|
12
|
+
const camera = ensuredCamera.value;
|
|
12
13
|
// ignore if no element
|
|
13
|
-
if (!renderer?.domElement || !scene)
|
|
14
|
+
if (!renderer?.domElement || !scene || !camera)
|
|
14
15
|
return;
|
|
15
16
|
width = width ?? window.innerWidth;
|
|
16
17
|
height = height ?? window.innerHeight;
|
|
17
18
|
// update camera
|
|
18
19
|
const aspect = width / height;
|
|
19
|
-
const camera = ensuredCamera.value;
|
|
20
20
|
if (camera.type?.toLowerCase() === 'perspectivecamera') {
|
|
21
21
|
const perspectiveCamera = camera.instance;
|
|
22
22
|
perspectiveCamera.aspect = aspect;
|
|
23
23
|
perspectiveCamera.updateProjectionMatrix();
|
|
24
24
|
}
|
|
25
|
+
else if (camera.type?.toLowerCase() === 'orthographiccamera') {
|
|
26
|
+
// console.log('TODO: ortho camera update')
|
|
27
|
+
const orthoCamera = camera.instance;
|
|
28
|
+
const heightInTermsOfWidth = height / width;
|
|
29
|
+
orthoCamera.top = heightInTermsOfWidth * 10;
|
|
30
|
+
orthoCamera.bottom = -heightInTermsOfWidth * 10;
|
|
31
|
+
orthoCamera.right = 10;
|
|
32
|
+
orthoCamera.left = -10;
|
|
33
|
+
orthoCamera.updateProjectionMatrix();
|
|
34
|
+
}
|
|
25
35
|
else {
|
|
26
|
-
console.log('TODO: ortho camera
|
|
36
|
+
console.log('TODO: non-ortho or perspective camera');
|
|
27
37
|
}
|
|
28
38
|
// update canvas
|
|
29
39
|
renderer.setSize(width, height);
|
|
30
40
|
// render immediately so there's no flicker
|
|
31
41
|
if (scene && camera.instance) {
|
|
32
|
-
// const cameraInstance = scene.traverse(v => )
|
|
33
42
|
renderer.render(toRaw(scene), toRaw(camera.instance));
|
|
34
43
|
}
|
|
35
44
|
};
|
|
@@ -74,8 +83,13 @@ const LunchboxWrapper = {
|
|
|
74
83
|
props: {
|
|
75
84
|
// These should match the Lunchbox.WrapperProps interface
|
|
76
85
|
background: String,
|
|
86
|
+
cameraArgs: Array,
|
|
87
|
+
cameraLook: Array,
|
|
88
|
+
cameraLookAt: Array,
|
|
77
89
|
cameraPosition: Array,
|
|
78
90
|
dpr: Number,
|
|
91
|
+
ortho: Boolean,
|
|
92
|
+
orthographic: Boolean,
|
|
79
93
|
rendererProperties: Object,
|
|
80
94
|
shadow: [Boolean, Object],
|
|
81
95
|
transparent: Boolean,
|
|
@@ -86,6 +100,7 @@ const LunchboxWrapper = {
|
|
|
86
100
|
const dpr = ref(props.dpr ?? -1);
|
|
87
101
|
const container = ref();
|
|
88
102
|
let renderer;
|
|
103
|
+
let camera;
|
|
89
104
|
let scene;
|
|
90
105
|
// MOUNT
|
|
91
106
|
// ====================
|
|
@@ -93,12 +108,6 @@ const LunchboxWrapper = {
|
|
|
93
108
|
// canvas needs to exist
|
|
94
109
|
if (!canvas.value)
|
|
95
110
|
throw new Error('missing canvas');
|
|
96
|
-
// ensure camera
|
|
97
|
-
const camera = ensuredCamera.value.instance;
|
|
98
|
-
// move camera if needed
|
|
99
|
-
if (camera && props.cameraPosition) {
|
|
100
|
-
camera.position.set(...props.cameraPosition);
|
|
101
|
-
}
|
|
102
111
|
// RENDERER
|
|
103
112
|
// ====================
|
|
104
113
|
// is there already a renderer?
|
|
@@ -155,6 +164,47 @@ const LunchboxWrapper = {
|
|
|
155
164
|
rendererReady.value = true;
|
|
156
165
|
return;
|
|
157
166
|
}
|
|
167
|
+
// CAMERA
|
|
168
|
+
// ====================
|
|
169
|
+
// is there already a camera?
|
|
170
|
+
camera = tryGetNodeWithInstanceType([
|
|
171
|
+
'PerspectiveCamera',
|
|
172
|
+
'OrthographicCamera',
|
|
173
|
+
]);
|
|
174
|
+
// if not, let's create one
|
|
175
|
+
if (!camera) {
|
|
176
|
+
// create ortho camera
|
|
177
|
+
if (props.ortho || props.orthographic) {
|
|
178
|
+
ensuredCamera.value = createNode({
|
|
179
|
+
props: { args: props.cameraArgs ?? [] },
|
|
180
|
+
type: 'OrthographicCamera',
|
|
181
|
+
uuid: fallbackCameraUuid,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
ensuredCamera.value = createNode({
|
|
186
|
+
props: {
|
|
187
|
+
args: props.cameraArgs ?? [45, 0.5625, 1, 1000],
|
|
188
|
+
},
|
|
189
|
+
type: 'PerspectiveCamera',
|
|
190
|
+
uuid: fallbackCameraUuid,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
cameraReady.value = true;
|
|
194
|
+
camera = ensuredCamera.value;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
cameraReady.value = true;
|
|
198
|
+
}
|
|
199
|
+
// move camera if needed
|
|
200
|
+
if (camera && props.cameraPosition) {
|
|
201
|
+
camera.instance?.position.set(...props.cameraPosition);
|
|
202
|
+
}
|
|
203
|
+
// angle camera if needed
|
|
204
|
+
if (camera && (props.cameraLookAt || props.cameraLook)) {
|
|
205
|
+
const source = (props.cameraLookAt || props.cameraLook);
|
|
206
|
+
camera.instance?.lookAt(...source);
|
|
207
|
+
}
|
|
158
208
|
// SCENE
|
|
159
209
|
// ====================
|
|
160
210
|
scene = ensuredScene.value;
|
|
@@ -181,7 +231,7 @@ const LunchboxWrapper = {
|
|
|
181
231
|
// console.log(scene)
|
|
182
232
|
update({
|
|
183
233
|
app: getCurrentInstance().appContext.app,
|
|
184
|
-
camera,
|
|
234
|
+
camera: camera.instance,
|
|
185
235
|
renderer: renderer.instance,
|
|
186
236
|
scene: scene.instance,
|
|
187
237
|
});
|
|
@@ -211,21 +261,6 @@ const LunchboxWrapper = {
|
|
|
211
261
|
},
|
|
212
262
|
};
|
|
213
263
|
|
|
214
|
-
const catalogue = {};
|
|
215
|
-
|
|
216
|
-
const lunchboxDomComponentNames = [
|
|
217
|
-
'canvas',
|
|
218
|
-
'div',
|
|
219
|
-
'LunchboxWrapper',
|
|
220
|
-
];
|
|
221
|
-
// component creation utility
|
|
222
|
-
const createComponent$1 = (tag) => defineComponent({
|
|
223
|
-
inheritAttrs: false,
|
|
224
|
-
name: tag,
|
|
225
|
-
setup(props, context) {
|
|
226
|
-
return () => h(tag, context.attrs, context.slots?.default?.() || []);
|
|
227
|
-
},
|
|
228
|
-
});
|
|
229
264
|
// list of all components to register out of the box
|
|
230
265
|
const autoGeneratedComponents = [
|
|
231
266
|
// ThreeJS basics
|
|
@@ -338,21 +373,11 @@ const autoGeneratedComponents = [
|
|
|
338
373
|
'arrayCamera',
|
|
339
374
|
// renderers
|
|
340
375
|
'webGLRenderer',
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
});
|
|
345
|
-
const components = {
|
|
346
|
-
...autoGeneratedComponents,
|
|
347
|
-
'Lunchbox': LunchboxWrapper,
|
|
348
|
-
// Gltf,
|
|
349
|
-
};
|
|
350
|
-
// console.log(components, Gltf)
|
|
351
|
-
/*
|
|
352
|
-
// List copied from r3f
|
|
353
|
-
// https://github.com/pmndrs/react-three-fiber/blob/master/packages/fiber/src/three-types.ts
|
|
376
|
+
/*
|
|
377
|
+
// List copied from r3f:
|
|
378
|
+
// https://github.com/pmndrs/react-three-fiber/blob/master/packages/fiber/src/three-types.ts
|
|
354
379
|
|
|
355
|
-
// NOT IMPLEMENTED:
|
|
380
|
+
// NOT IMPLEMENTED (can be added via Extend - docs.lunchboxjs.com/components/extend/):
|
|
356
381
|
audioListener: AudioListenerProps
|
|
357
382
|
positionalAudio: PositionalAudioProps
|
|
358
383
|
|
|
@@ -400,6 +425,27 @@ const components = {
|
|
|
400
425
|
fogExp2: FogExp2Props
|
|
401
426
|
shape: ShapeProps
|
|
402
427
|
*/
|
|
428
|
+
];
|
|
429
|
+
|
|
430
|
+
const catalogue = {};
|
|
431
|
+
|
|
432
|
+
const lunchboxDomComponentNames = ['canvas', 'div', 'LunchboxWrapper'];
|
|
433
|
+
// component creation utility
|
|
434
|
+
const createComponent$1 = (tag) => defineComponent({
|
|
435
|
+
inheritAttrs: false,
|
|
436
|
+
name: tag,
|
|
437
|
+
setup(props, context) {
|
|
438
|
+
return () => h(tag, context.attrs, context.slots?.default?.() || []);
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
autoGeneratedComponents.map(createComponent$1).reduce((acc, curr) => {
|
|
442
|
+
acc[curr.name] = curr;
|
|
443
|
+
return acc;
|
|
444
|
+
});
|
|
445
|
+
const components = {
|
|
446
|
+
...autoGeneratedComponents,
|
|
447
|
+
Lunchbox: LunchboxWrapper,
|
|
448
|
+
};
|
|
403
449
|
|
|
404
450
|
function find(target) {
|
|
405
451
|
target = isRef(target) ? target.value : target;
|
|
@@ -561,6 +607,7 @@ function addEventListener({ node, key, value, }) {
|
|
|
561
607
|
// register click, pointerdown, pointerup
|
|
562
608
|
if (key === 'onClick' || key === 'onPointerDown' || key === 'onPointerUp') {
|
|
563
609
|
const stop = watch(() => inputActive.value, (isDown) => {
|
|
610
|
+
console.log(isDown, currentIntersections);
|
|
564
611
|
const idx = currentIntersections
|
|
565
612
|
.map((v) => v.element)
|
|
566
613
|
.findIndex((v) => v.instance &&
|
|
@@ -828,9 +875,27 @@ function buildEnsured(pascalCaseTypes, fallbackUuid, props = {}, callback = null
|
|
|
828
875
|
// ENSURE CAMERA
|
|
829
876
|
// ====================
|
|
830
877
|
const fallbackCameraUuid = 'FALLBACK_CAMERA';
|
|
831
|
-
const
|
|
832
|
-
|
|
878
|
+
const defaultCamera = buildEnsured(['PerspectiveCamera', 'OrthographicCamera'], fallbackCameraUuid, { args: [45, 0.5625, 1, 1000] });
|
|
879
|
+
/** Special value to be changed ONLY in `LunchboxWrapper`.
|
|
880
|
+
* Functions waiting for a Camera need to wait for this to be true. */
|
|
881
|
+
const cameraReady = ref(false);
|
|
882
|
+
const ensuredCamera = computed({
|
|
883
|
+
get() {
|
|
884
|
+
return (cameraReady.value ? defaultCamera.value : null);
|
|
885
|
+
},
|
|
886
|
+
set(val) {
|
|
887
|
+
const t = val.type ?? '';
|
|
888
|
+
const pascalType = t[0].toUpperCase() + t.slice(1);
|
|
889
|
+
overrides[pascalType] = val;
|
|
890
|
+
},
|
|
833
891
|
});
|
|
892
|
+
// export const ensuredCamera = buildEnsured<THREE.Camera>(
|
|
893
|
+
// ['PerspectiveCamera', 'OrthographicCamera'],
|
|
894
|
+
// fallbackCameraUuid,
|
|
895
|
+
// {
|
|
896
|
+
// args: [45, 0.5625, 1, 1000],
|
|
897
|
+
// }
|
|
898
|
+
// )
|
|
834
899
|
// ENSURE RENDERER
|
|
835
900
|
// ====================
|
|
836
901
|
const fallbackRendererUuid = 'FALLBACK_RENDERER';
|
|
@@ -1179,12 +1244,14 @@ let frameID;
|
|
|
1179
1244
|
const beforeRender = [];
|
|
1180
1245
|
const afterRender = [];
|
|
1181
1246
|
const update = (opts) => {
|
|
1247
|
+
// request next frame
|
|
1182
1248
|
frameID = requestAnimationFrame(() => update({
|
|
1183
1249
|
app: opts.app,
|
|
1184
1250
|
renderer: ensureRenderer.value?.instance,
|
|
1185
1251
|
scene: ensuredScene.value.instance,
|
|
1186
|
-
camera: ensuredCamera.value
|
|
1252
|
+
camera: ensuredCamera.value?.instance,
|
|
1187
1253
|
}));
|
|
1254
|
+
// prep options
|
|
1188
1255
|
const { app, renderer, scene, camera } = opts;
|
|
1189
1256
|
// BEFORE RENDER
|
|
1190
1257
|
beforeRender.forEach((cb) => {
|
|
@@ -1193,9 +1260,13 @@ const update = (opts) => {
|
|
|
1193
1260
|
}
|
|
1194
1261
|
});
|
|
1195
1262
|
// RENDER
|
|
1196
|
-
// console.log(camera?.position.z)
|
|
1197
1263
|
if (renderer && scene && camera) {
|
|
1198
|
-
|
|
1264
|
+
if (app.customRender) {
|
|
1265
|
+
app.customRender(opts);
|
|
1266
|
+
}
|
|
1267
|
+
else {
|
|
1268
|
+
renderer.render(toRaw(scene), toRaw(camera));
|
|
1269
|
+
}
|
|
1199
1270
|
}
|
|
1200
1271
|
// AFTER RENDER
|
|
1201
1272
|
afterRender.forEach((cb) => {
|
|
@@ -1212,6 +1283,15 @@ const onBeforeRender = (cb, index = Infinity) => {
|
|
|
1212
1283
|
beforeRender.splice(index, 0, cb);
|
|
1213
1284
|
}
|
|
1214
1285
|
};
|
|
1286
|
+
const offBeforeRender = (cb) => {
|
|
1287
|
+
if (isFinite(cb)) {
|
|
1288
|
+
beforeRender.splice(cb, 1);
|
|
1289
|
+
}
|
|
1290
|
+
else {
|
|
1291
|
+
const idx = beforeRender.findIndex((v) => v == cb);
|
|
1292
|
+
beforeRender.splice(idx, 1);
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1215
1295
|
const onAfterRender = (cb, index = Infinity) => {
|
|
1216
1296
|
if (index === Infinity) {
|
|
1217
1297
|
afterRender.push(cb);
|
|
@@ -1220,6 +1300,15 @@ const onAfterRender = (cb, index = Infinity) => {
|
|
|
1220
1300
|
afterRender.splice(index, 0, cb);
|
|
1221
1301
|
}
|
|
1222
1302
|
};
|
|
1303
|
+
const offAfterRender = (cb) => {
|
|
1304
|
+
if (isFinite(cb)) {
|
|
1305
|
+
afterRender.splice(cb, 1);
|
|
1306
|
+
}
|
|
1307
|
+
else {
|
|
1308
|
+
const idx = afterRender.findIndex((v) => v == cb);
|
|
1309
|
+
afterRender.splice(idx, 1);
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1223
1312
|
const cancelUpdate = () => {
|
|
1224
1313
|
if (frameID)
|
|
1225
1314
|
cancelAnimationFrame(frameID);
|
|
@@ -1573,11 +1662,33 @@ const globals = {
|
|
|
1573
1662
|
inputActive,
|
|
1574
1663
|
mousePos,
|
|
1575
1664
|
};
|
|
1576
|
-
const camera = computed(() => ensuredCamera.value
|
|
1665
|
+
const camera = computed(() => ensuredCamera.value?.instance ?? null);
|
|
1577
1666
|
const renderer = computed(() => ensureRenderer.value?.instance ?? null);
|
|
1578
1667
|
const scene = computed(() => ensuredScene.value.instance);
|
|
1668
|
+
// CUSTOM RENDER SUPPORT
|
|
1669
|
+
// ====================
|
|
1670
|
+
let app = null;
|
|
1671
|
+
let queuedCustomRenderFunction = null;
|
|
1672
|
+
/** Set a custom render function, overriding the Lunchbox app's default render function.
|
|
1673
|
+
* Changing this requires the user to manually render their scene.
|
|
1674
|
+
*/
|
|
1675
|
+
const setCustomRender = (render) => {
|
|
1676
|
+
if (app)
|
|
1677
|
+
app.setCustomRender(render);
|
|
1678
|
+
else
|
|
1679
|
+
queuedCustomRenderFunction = render;
|
|
1680
|
+
};
|
|
1681
|
+
/** Clear the active app's custom render function. */
|
|
1682
|
+
const clearCustomRender = () => {
|
|
1683
|
+
if (app)
|
|
1684
|
+
app.clearCustomRender();
|
|
1685
|
+
else
|
|
1686
|
+
queuedCustomRenderFunction = null;
|
|
1687
|
+
};
|
|
1688
|
+
// CREATE APP
|
|
1689
|
+
// ====================
|
|
1579
1690
|
const createApp = (root) => {
|
|
1580
|
-
|
|
1691
|
+
app = createRenderer(nodeOps).createApp(root);
|
|
1581
1692
|
// register all components
|
|
1582
1693
|
Object.keys(components).forEach((key) => {
|
|
1583
1694
|
app.component(key, components[key]);
|
|
@@ -1600,11 +1711,24 @@ const createApp = (root) => {
|
|
|
1600
1711
|
};
|
|
1601
1712
|
// embed .extend function
|
|
1602
1713
|
app.extend = (targets) => {
|
|
1603
|
-
extend({ app, ...targets });
|
|
1714
|
+
extend({ app: app, ...targets });
|
|
1604
1715
|
return app;
|
|
1605
1716
|
};
|
|
1717
|
+
// prep for custom render support
|
|
1718
|
+
app.setCustomRender = (newRender) => {
|
|
1719
|
+
app.customRender = newRender;
|
|
1720
|
+
};
|
|
1721
|
+
// add queued custom render if we have one
|
|
1722
|
+
if (queuedCustomRenderFunction) {
|
|
1723
|
+
app.setCustomRender(queuedCustomRenderFunction);
|
|
1724
|
+
queuedCustomRenderFunction = null;
|
|
1725
|
+
}
|
|
1726
|
+
// add custom render removal
|
|
1727
|
+
app.clearCustomRender = () => {
|
|
1728
|
+
app.customRender = null;
|
|
1729
|
+
};
|
|
1606
1730
|
// done
|
|
1607
1731
|
return app;
|
|
1608
1732
|
};
|
|
1609
1733
|
|
|
1610
|
-
export { camera, createApp, find, globals, lunchboxRootNode as lunchboxTree, onAfterRender, onBeforeRender, renderer, scene,
|
|
1734
|
+
export { autoGeneratedComponents, camera, clearCustomRender, createApp, find, globals, lunchboxRootNode as lunchboxTree, offAfterRender, offBeforeRender, onAfterRender, onBeforeRender, renderer, scene, setCustomRender };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lunchboxjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4006-dev002",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "vite -c utils/vite.config.ts",
|
|
6
6
|
"build": "vue-tsc --noEmit && vite build -c utils/vite.config.ts",
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"@types/three": "0.133.0",
|
|
26
26
|
"@types/uuid": "8.3.1",
|
|
27
27
|
"@vitejs/plugin-vue": "^1.9.3",
|
|
28
|
+
"chroma-js": "2.1.2",
|
|
29
|
+
"nice-color-palettes": "3.0.0",
|
|
28
30
|
"rollup-plugin-delete": "2.0.0",
|
|
29
31
|
"rollup-plugin-terser": "7.0.2",
|
|
30
32
|
"typescript": "^4.4.3",
|
|
@@ -8,11 +8,13 @@ import {
|
|
|
8
8
|
WritableComputedRef,
|
|
9
9
|
} from 'vue'
|
|
10
10
|
import {
|
|
11
|
+
cameraReady,
|
|
11
12
|
cancelUpdate,
|
|
12
13
|
createNode,
|
|
13
14
|
ensuredCamera,
|
|
14
15
|
ensureRenderer,
|
|
15
16
|
ensuredScene,
|
|
17
|
+
fallbackCameraUuid,
|
|
16
18
|
fallbackRendererUuid,
|
|
17
19
|
MiniDom,
|
|
18
20
|
rendererReady,
|
|
@@ -21,7 +23,7 @@ import {
|
|
|
21
23
|
} from '../../core'
|
|
22
24
|
import { set } from 'lodash'
|
|
23
25
|
import { globals, Lunch } from '../..'
|
|
24
|
-
import { Color } from 'three'
|
|
26
|
+
import { Color, Vector2 } from 'three'
|
|
25
27
|
import { prepCanvas } from './prepCanvas'
|
|
26
28
|
|
|
27
29
|
/** fixed & fill styling for container */
|
|
@@ -42,8 +44,13 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
42
44
|
props: {
|
|
43
45
|
// These should match the Lunchbox.WrapperProps interface
|
|
44
46
|
background: String,
|
|
47
|
+
cameraArgs: Array,
|
|
48
|
+
cameraLook: Array,
|
|
49
|
+
cameraLookAt: Array,
|
|
45
50
|
cameraPosition: Array,
|
|
46
51
|
dpr: Number,
|
|
52
|
+
ortho: Boolean,
|
|
53
|
+
orthographic: Boolean,
|
|
47
54
|
rendererProperties: Object,
|
|
48
55
|
shadow: [Boolean, Object],
|
|
49
56
|
transparent: Boolean,
|
|
@@ -54,6 +61,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
54
61
|
const dpr = ref(props.dpr ?? -1)
|
|
55
62
|
const container = ref<MiniDom.RendererDomNode>()
|
|
56
63
|
let renderer: Lunch.Node<THREE.WebGLRenderer> | null
|
|
64
|
+
let camera: Lunch.Node<THREE.Camera> | null
|
|
57
65
|
let scene: MiniDom.RendererStandardNode<THREE.Scene>
|
|
58
66
|
|
|
59
67
|
// MOUNT
|
|
@@ -62,13 +70,6 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
62
70
|
// canvas needs to exist
|
|
63
71
|
if (!canvas.value) throw new Error('missing canvas')
|
|
64
72
|
|
|
65
|
-
// ensure camera
|
|
66
|
-
const camera = ensuredCamera.value.instance
|
|
67
|
-
// move camera if needed
|
|
68
|
-
if (camera && props.cameraPosition) {
|
|
69
|
-
camera.position.set(...props.cameraPosition)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
73
|
// RENDERER
|
|
73
74
|
// ====================
|
|
74
75
|
// is there already a renderer?
|
|
@@ -139,6 +140,48 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
139
140
|
return
|
|
140
141
|
}
|
|
141
142
|
|
|
143
|
+
// CAMERA
|
|
144
|
+
// ====================
|
|
145
|
+
// is there already a camera?
|
|
146
|
+
camera = tryGetNodeWithInstanceType([
|
|
147
|
+
'PerspectiveCamera',
|
|
148
|
+
'OrthographicCamera',
|
|
149
|
+
])
|
|
150
|
+
// if not, let's create one
|
|
151
|
+
if (!camera) {
|
|
152
|
+
// create ortho camera
|
|
153
|
+
if (props.ortho || props.orthographic) {
|
|
154
|
+
ensuredCamera.value = createNode<THREE.OrthographicCamera>({
|
|
155
|
+
props: { args: props.cameraArgs ?? [] },
|
|
156
|
+
type: 'OrthographicCamera',
|
|
157
|
+
uuid: fallbackCameraUuid,
|
|
158
|
+
})
|
|
159
|
+
} else {
|
|
160
|
+
ensuredCamera.value = createNode<THREE.PerspectiveCamera>({
|
|
161
|
+
props: {
|
|
162
|
+
args: props.cameraArgs ?? [45, 0.5625, 1, 1000],
|
|
163
|
+
},
|
|
164
|
+
type: 'PerspectiveCamera',
|
|
165
|
+
uuid: fallbackCameraUuid,
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
cameraReady.value = true
|
|
170
|
+
|
|
171
|
+
camera = ensuredCamera.value
|
|
172
|
+
} else {
|
|
173
|
+
cameraReady.value = true
|
|
174
|
+
}
|
|
175
|
+
// move camera if needed
|
|
176
|
+
if (camera && props.cameraPosition) {
|
|
177
|
+
camera.instance?.position.set(...props.cameraPosition)
|
|
178
|
+
}
|
|
179
|
+
// angle camera if needed
|
|
180
|
+
if (camera && (props.cameraLookAt || props.cameraLook)) {
|
|
181
|
+
const source = (props.cameraLookAt || props.cameraLook)!
|
|
182
|
+
camera.instance?.lookAt(...source)
|
|
183
|
+
}
|
|
184
|
+
|
|
142
185
|
// SCENE
|
|
143
186
|
// ====================
|
|
144
187
|
scene = ensuredScene.value
|
|
@@ -171,7 +214,7 @@ export const LunchboxWrapper: ComponentOptions = {
|
|
|
171
214
|
// console.log(scene)
|
|
172
215
|
update({
|
|
173
216
|
app: getCurrentInstance()!.appContext.app as Lunch.App,
|
|
174
|
-
camera,
|
|
217
|
+
camera: camera.instance,
|
|
175
218
|
renderer: renderer.instance,
|
|
176
219
|
scene: scene.instance,
|
|
177
220
|
})
|
|
@@ -4,29 +4,37 @@ import { toRaw } from 'vue'
|
|
|
4
4
|
export const resizeCanvas = (width?: number, height?: number) => {
|
|
5
5
|
const renderer = ensureRenderer.value?.instance
|
|
6
6
|
const scene = ensuredScene.value.instance
|
|
7
|
+
const camera = ensuredCamera.value
|
|
7
8
|
|
|
8
9
|
// ignore if no element
|
|
9
|
-
if (!renderer?.domElement || !scene) return
|
|
10
|
+
if (!renderer?.domElement || !scene || !camera) return
|
|
10
11
|
|
|
11
12
|
width = width ?? window.innerWidth
|
|
12
13
|
height = height ?? window.innerHeight
|
|
13
14
|
|
|
14
15
|
// update camera
|
|
15
16
|
const aspect = width / height
|
|
16
|
-
const camera = ensuredCamera.value
|
|
17
17
|
if (camera.type?.toLowerCase() === 'perspectivecamera') {
|
|
18
18
|
const perspectiveCamera = camera.instance as THREE.PerspectiveCamera
|
|
19
19
|
perspectiveCamera.aspect = aspect
|
|
20
20
|
perspectiveCamera.updateProjectionMatrix()
|
|
21
|
+
} else if (camera.type?.toLowerCase() === 'orthographiccamera') {
|
|
22
|
+
// console.log('TODO: ortho camera update')
|
|
23
|
+
const orthoCamera = camera.instance as THREE.OrthographicCamera
|
|
24
|
+
const heightInTermsOfWidth = height / width
|
|
25
|
+
orthoCamera.top = heightInTermsOfWidth * 10
|
|
26
|
+
orthoCamera.bottom = -heightInTermsOfWidth * 10
|
|
27
|
+
orthoCamera.right = 10
|
|
28
|
+
orthoCamera.left = -10
|
|
29
|
+
orthoCamera.updateProjectionMatrix()
|
|
21
30
|
} else {
|
|
22
|
-
console.log('TODO: ortho camera
|
|
31
|
+
console.log('TODO: non-ortho or perspective camera')
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
// update canvas
|
|
26
35
|
renderer.setSize(width, height)
|
|
27
36
|
// render immediately so there's no flicker
|
|
28
37
|
if (scene && camera.instance) {
|
|
29
|
-
// const cameraInstance = scene.traverse(v => )
|
|
30
38
|
renderer.render(toRaw(scene), toRaw(camera.instance))
|
|
31
39
|
}
|
|
32
40
|
}
|