feat: new camera control and scene implemented
This commit is contained in:
parent
27876c1aae
commit
97d4590da4
8 changed files with 380 additions and 4 deletions
152
client/package-lock.json
generated
152
client/package-lock.json
generated
|
@ -11,12 +11,14 @@
|
||||||
"@fontsource/roboto": "^5.0.8",
|
"@fontsource/roboto": "^5.0.8",
|
||||||
"@threlte/core": "^7.1.0",
|
"@threlte/core": "^7.1.0",
|
||||||
"@threlte/extras": "^8.8.0",
|
"@threlte/extras": "^8.8.0",
|
||||||
|
"camera-controls": "^2.8.3",
|
||||||
"howler": "^2.2.4",
|
"howler": "^2.2.4",
|
||||||
"material-icons": "^1.13.12",
|
"material-icons": "^1.13.12",
|
||||||
"material-symbols": "^0.15.0",
|
"material-symbols": "^0.15.0",
|
||||||
"overlayscrollbars-svelte": "^0.5.3",
|
"overlayscrollbars-svelte": "^0.5.3",
|
||||||
"socket.io-client": "^4.7.4",
|
"socket.io-client": "^4.7.4",
|
||||||
"svelte-french-toast": "^1.2.0",
|
"svelte-french-toast": "^1.2.0",
|
||||||
|
"svelte-tweakpane-ui": "^1.2.1",
|
||||||
"three": "^0.161.0"
|
"three": "^0.161.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1035,6 +1037,11 @@
|
||||||
"integrity": "sha512-BRbo1fOtyVbhfLyuCWw6wAWp+U8UQle+ZXu84MYYWzYSEB28dyfnRBIE99eoG+qdAC0po6L2ScIEivcT07UaMA==",
|
"integrity": "sha512-BRbo1fOtyVbhfLyuCWw6wAWp+U8UQle+ZXu84MYYWzYSEB28dyfnRBIE99eoG+qdAC0po6L2ScIEivcT07UaMA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@tweakpane/core": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-qHci4XA1Wngpwy8IzsLh5JEdscz8aDti/9YhyOaq01si+cgNDaZfwzTtXdn1+xTxSnCM+pW4Zb2/4eqn+K1ATw=="
|
||||||
|
},
|
||||||
"node_modules/@types/cookie": {
|
"node_modules/@types/cookie": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||||
|
@ -1300,6 +1307,14 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/camera-controls": {
|
||||||
|
"version": "2.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.8.3.tgz",
|
||||||
|
"integrity": "sha512-zFjqUR6onLkG+z1A6vAWfzovxZxWVSvp6e5t3lfZgfgPZtX3n74aykNAUaoRbq8Y3tOxadHkDjbfGDOP9hFf2w==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"three": ">=0.126.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001588",
|
"version": "1.0.30001588",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz",
|
||||||
|
@ -1592,9 +1607,7 @@
|
||||||
"node_modules/esm-env": {
|
"node_modules/esm-env": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz",
|
||||||
"integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==",
|
"integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA=="
|
||||||
"dev": true,
|
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/estree-walker": {
|
"node_modules/estree-walker": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
|
@ -1604,6 +1617,19 @@
|
||||||
"@types/estree": "^1.0.0"
|
"@types/estree": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-copy": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA=="
|
||||||
|
},
|
||||||
|
"node_modules/fast-equals": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||||
|
@ -2972,6 +2998,17 @@
|
||||||
"svelte": "^3.19.0 || ^4.0.0"
|
"svelte": "^3.19.0 || ^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svelte-local-storage-store": {
|
||||||
|
"version": "0.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-local-storage-store/-/svelte-local-storage-store-0.6.4.tgz",
|
||||||
|
"integrity": "sha512-45WoY2vSGPQM1sIQJ9jTkPPj20hYeqm+af6mUGRFSPP5WglZf36YYoZqwmZZ8Dt/2SU8lem+BTA8/Z/8TkqNLg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.14"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": "^3.48.0 || >4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/svelte-preprocess": {
|
"node_modules/svelte-preprocess": {
|
||||||
"version": "5.1.3",
|
"version": "5.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz",
|
||||||
|
@ -3035,6 +3072,115 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-tweakpane-ui/-/svelte-tweakpane-ui-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-F62AFvZiqhXa0E3HMpUdmdWWyus/C+nTBFrFd/vEhHP6dYOQ4EN9qwvjdybL90DZFTIwkZe3w4oSbEGn1muKkQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@0b5vr/tweakpane-plugin-profiler": "^0.4.1",
|
||||||
|
"@0b5vr/tweakpane-plugin-rotation": "^0.2.0",
|
||||||
|
"@kitschpatrol/tweakpane-image-plugin": "^2.0.0",
|
||||||
|
"@pangenerator/tweakpane-textarea-plugin": "^2.0.0",
|
||||||
|
"@tweakpane/core": "^2.0.3",
|
||||||
|
"@tweakpane/plugin-camerakit": "^0.3.0",
|
||||||
|
"@tweakpane/plugin-essentials": "^0.2.1",
|
||||||
|
"esm-env": "^1.0.0",
|
||||||
|
"fast-copy": "^3.0.1",
|
||||||
|
"fast-equals": "^5.0.1",
|
||||||
|
"nanoid": "^5.0.6",
|
||||||
|
"svelte-local-storage-store": "^0.6.4",
|
||||||
|
"tweakpane": "^4.0.3",
|
||||||
|
"tweakpane-plugin-waveform": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0",
|
||||||
|
"pnpm": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/@0b5vr/tweakpane-plugin-profiler": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@0b5vr/tweakpane-plugin-profiler/-/tweakpane-plugin-profiler-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-jgkPbT24eQ7isj8F7/IsbdqrwvBoWBmwjqxdP35smD2D6xsx+9viR57SKBxi9PxTZDEayicmCzBk++0PTqRnBg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"tweakpane": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/@0b5vr/tweakpane-plugin-rotation": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@0b5vr/tweakpane-plugin-rotation/-/tweakpane-plugin-rotation-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-LK+84kNTusEepVwiKH6ib/Pd+5RxI3UC4rHxn5c14GO58QS49Hh0ft3hFXt/NDzYEST17Q9qg96BcpclhCzYYQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"tweakpane": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/@kitschpatrol/tweakpane-image-plugin": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@kitschpatrol/tweakpane-image-plugin/-/tweakpane-image-plugin-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BzEZqIhD/dM7AW0Ebv+309L4k8ZZJ5fC9Zks4sozVK3FwJooviE6JzaFAuB7k0M5oX45Wyn59tQXdHafgsP3YA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"tweakpane": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/@pangenerator/tweakpane-textarea-plugin": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@pangenerator/tweakpane-textarea-plugin/-/tweakpane-textarea-plugin-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BERPuuyJYWvtJzXh4wtgYspza0ihigE2m4qs57ERKtWG59+lI2t/2TOXlwz7Xyx/QEIH25uO1g732YCljgKaUw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"tweakpane": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/@tweakpane/plugin-camerakit": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tweakpane/plugin-camerakit/-/plugin-camerakit-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-6UwgwDKU+oaAgXJ2D/pOoIpEAZts0RyeLmVzBJGs+VVNqSfkiHzL0i5XD+XnmSL2PaLXBne0dlz0bYOrjmeELw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"tweakpane": "^4.0.0-beta.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/@tweakpane/plugin-essentials": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tweakpane/plugin-essentials/-/plugin-essentials-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-VbFU1/uD+CJNFQdfLXUOLjeG5HyUZH97Ox9CxmyVetg1hqjVun3C83HAGFULyhKzl8tSgii8jr304r8QpdHwzQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"tweakpane": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/nanoid": {
|
||||||
|
"version": "5.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.6.tgz",
|
||||||
|
"integrity": "sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || >=20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/tweakpane": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-BlcWOAe8oe4c+k9pmLBARGdWB6MVZMszayekkixQXTgkxTaYoTUpHpwVEp+3HkoamZkomodpbBf0CkguIHTgLg==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/cocopon"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/svelte-tweakpane-ui/node_modules/tweakpane-plugin-waveform": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweakpane-plugin-waveform/-/tweakpane-plugin-waveform-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-fyTRe6Emt7YpgHC5iiTZgk6RHflNm5VIOAsl2+l3mm96+KE8I+7sNPeyADxKcfcQF23c7/R3La5WNhaHNyeJag==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"tweakpane": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/svelte-writable-derived": {
|
"node_modules/svelte-writable-derived": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-writable-derived/-/svelte-writable-derived-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-writable-derived/-/svelte-writable-derived-3.1.0.tgz",
|
||||||
|
|
|
@ -31,12 +31,14 @@
|
||||||
"@fontsource/roboto": "^5.0.8",
|
"@fontsource/roboto": "^5.0.8",
|
||||||
"@threlte/core": "^7.1.0",
|
"@threlte/core": "^7.1.0",
|
||||||
"@threlte/extras": "^8.8.0",
|
"@threlte/extras": "^8.8.0",
|
||||||
|
"camera-controls": "^2.8.3",
|
||||||
"howler": "^2.2.4",
|
"howler": "^2.2.4",
|
||||||
"material-icons": "^1.13.12",
|
"material-icons": "^1.13.12",
|
||||||
"material-symbols": "^0.15.0",
|
"material-symbols": "^0.15.0",
|
||||||
"overlayscrollbars-svelte": "^0.5.3",
|
"overlayscrollbars-svelte": "^0.5.3",
|
||||||
"socket.io-client": "^4.7.4",
|
"socket.io-client": "^4.7.4",
|
||||||
"svelte-french-toast": "^1.2.0",
|
"svelte-french-toast": "^1.2.0",
|
||||||
|
"svelte-tweakpane-ui": "^1.2.1",
|
||||||
"three": "^0.161.0"
|
"three": "^0.161.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
<script context="module" lang="ts">
|
||||||
|
let installed = false
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
T,
|
||||||
|
forwardEventHandlers,
|
||||||
|
useTask,
|
||||||
|
useParent,
|
||||||
|
useThrelte,
|
||||||
|
} from '@threlte/core'
|
||||||
|
import type {
|
||||||
|
CameraControlsEvents,
|
||||||
|
CameraControlsProps,
|
||||||
|
CameraControlsSlots,
|
||||||
|
} from './CameraControls.svelte'
|
||||||
|
|
||||||
|
type $$Props = CameraControlsProps
|
||||||
|
type $$Events = CameraControlsEvents
|
||||||
|
type $$Slots = CameraControlsSlots
|
||||||
|
|
||||||
|
import CameraControls from 'camera-controls'
|
||||||
|
import {
|
||||||
|
Box3,
|
||||||
|
Matrix4,
|
||||||
|
Quaternion,
|
||||||
|
Raycaster,
|
||||||
|
Sphere,
|
||||||
|
Spherical,
|
||||||
|
Vector2,
|
||||||
|
Vector3,
|
||||||
|
Vector4,
|
||||||
|
type PerspectiveCamera,
|
||||||
|
} from 'three'
|
||||||
|
import { DEG2RAD } from 'three/src/math/MathUtils'
|
||||||
|
|
||||||
|
const subsetOfTHREE = {
|
||||||
|
Vector2,
|
||||||
|
Vector3,
|
||||||
|
Vector4,
|
||||||
|
Quaternion,
|
||||||
|
Matrix4,
|
||||||
|
Spherical,
|
||||||
|
Box3,
|
||||||
|
Sphere,
|
||||||
|
Raycaster,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!installed) {
|
||||||
|
CameraControls.install({ THREE: subsetOfTHREE })
|
||||||
|
installed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = useParent()
|
||||||
|
|
||||||
|
if (!$parent) {
|
||||||
|
throw new Error('CameraControls must be a child of a ThreeJS camera')
|
||||||
|
}
|
||||||
|
|
||||||
|
const { renderer, invalidate } = useThrelte()
|
||||||
|
|
||||||
|
export let autoRotate = false
|
||||||
|
export let autoRotateSpeed = 1
|
||||||
|
|
||||||
|
export const ref = new CameraControls(
|
||||||
|
$parent as PerspectiveCamera,
|
||||||
|
renderer?.domElement
|
||||||
|
)
|
||||||
|
|
||||||
|
const getControls = () => ref
|
||||||
|
|
||||||
|
let disableAutoRotate = false
|
||||||
|
|
||||||
|
useTask(
|
||||||
|
delta => {
|
||||||
|
if (autoRotate && !disableAutoRotate) {
|
||||||
|
getControls().azimuthAngle += 4 * delta * DEG2RAD * autoRotateSpeed
|
||||||
|
}
|
||||||
|
const updated = getControls().update(delta)
|
||||||
|
if (updated) invalidate()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
autoInvalidate: false,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const forwardingComponent = forwardEventHandlers()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<T
|
||||||
|
is={ref}
|
||||||
|
on:controlstart={e => {
|
||||||
|
disableAutoRotate = true
|
||||||
|
}}
|
||||||
|
on:zoom={e => {
|
||||||
|
console.log('zoomstart', e)
|
||||||
|
}}
|
||||||
|
on:controlend={() => {
|
||||||
|
disableAutoRotate = false
|
||||||
|
}}
|
||||||
|
{...$$restProps}
|
||||||
|
bind:this={$forwardingComponent}
|
||||||
|
>
|
||||||
|
<slot {ref} />
|
||||||
|
</T>
|
16
client/src/lib/Dashboard/Visualization/CameraControls/CameraControls.svelte.d.ts
vendored
Normal file
16
client/src/lib/Dashboard/Visualization/CameraControls/CameraControls.svelte.d.ts
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import type { Events, Props, Slots } from '@threlte/core'
|
||||||
|
import CC from 'camera-controls'
|
||||||
|
import type { SvelteComponent } from 'svelte'
|
||||||
|
|
||||||
|
export type CameraControlsProps = Props<CC> & {
|
||||||
|
autoRotate?: boolean
|
||||||
|
autoRotateSpeed?: number
|
||||||
|
}
|
||||||
|
export type CameraControlsEvents = Events<CC>
|
||||||
|
export type CameraControlsSlots = Slots<CC>
|
||||||
|
|
||||||
|
export default class CameraControls extends SvelteComponent<
|
||||||
|
CameraControlsProps,
|
||||||
|
CameraControlsEvents,
|
||||||
|
CameraControlsSlots
|
||||||
|
> {}
|
|
@ -0,0 +1,39 @@
|
||||||
|
<script>
|
||||||
|
import { T, useTask } from '@threlte/core'
|
||||||
|
import { Grid } from '@threlte/extras'
|
||||||
|
import CameraControls from './CameraControls.svelte'
|
||||||
|
import { cameraControls, mesh } from './utils/cameraStore'
|
||||||
|
import Hornet from '../models/Hornet.svelte'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<T.PerspectiveCamera
|
||||||
|
makeDefault
|
||||||
|
position={[10, 10, 10]}
|
||||||
|
on:create={({ ref }) => {
|
||||||
|
ref.lookAt(0, 1, 0)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CameraControls
|
||||||
|
on:create={({ ref }) => {
|
||||||
|
$cameraControls = ref
|
||||||
|
}}
|
||||||
|
autoRotate
|
||||||
|
/>
|
||||||
|
</T.PerspectiveCamera>
|
||||||
|
|
||||||
|
<T.DirectionalLight position={[3, 10, 7]} />
|
||||||
|
|
||||||
|
<Hornet
|
||||||
|
position.y={1}
|
||||||
|
on:create={({ ref }) => {
|
||||||
|
$mesh = ref
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
sectionColor={'#ff3e00'}
|
||||||
|
sectionThickness={1}
|
||||||
|
cellColor={'#cccccc'}
|
||||||
|
gridSize={40}
|
||||||
|
infiniteGrid
|
||||||
|
/>
|
|
@ -0,0 +1,6 @@
|
||||||
|
import type CameraControls from 'camera-controls'
|
||||||
|
import { writable } from 'svelte/store'
|
||||||
|
import Hornet from '../../models/Hornet.svelte'
|
||||||
|
|
||||||
|
export const cameraControls = writable<CameraControls>()
|
||||||
|
export const mesh = writable()
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { useThrelteUserContext } from '@threlte/core'
|
||||||
|
import { writable, type Writable } from 'svelte/store'
|
||||||
|
import type { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
|
||||||
|
|
||||||
|
type ControlsContext = {
|
||||||
|
orbitControls: Writable<OrbitControls | undefined>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ### `useControlsContext`
|
||||||
|
*
|
||||||
|
* This hook is used to register the `OrbitControls` instance with the
|
||||||
|
* `ControlsContext`. We're using this context to enable and disable the
|
||||||
|
* controls when the user is interacting with the TransformControls.
|
||||||
|
*/
|
||||||
|
export const useControlsContext = (): ControlsContext => {
|
||||||
|
return useThrelteUserContext<ControlsContext>('threlte-controls', {
|
||||||
|
orbitControls: writable<OrbitControls | undefined>(undefined),
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,6 +1,47 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Canvas } from '@threlte/core'
|
import { Canvas } from '@threlte/core'
|
||||||
import Scene from './Scene.svelte'
|
// @ts-expect-error
|
||||||
|
import { DEG2RAD } from 'three/src/math/MathUtils'
|
||||||
|
import { Pane, Button, Separator } from 'svelte-tweakpane-ui'
|
||||||
|
import { cameraControls, mesh } from './CameraControls/utils/cameraStore'
|
||||||
|
import Scene from './CameraControls/Scene.svelte'
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
import {
|
||||||
|
Vector3,
|
||||||
|
type OrthographicCamera,
|
||||||
|
type PerspectiveCamera,
|
||||||
|
} from 'three'
|
||||||
|
|
||||||
|
let camera: PerspectiveCamera | OrthographicCamera
|
||||||
|
|
||||||
|
$: if ($cameraControls) {
|
||||||
|
// @ts-expect-error
|
||||||
|
camera = $cameraControls._camera
|
||||||
|
}
|
||||||
|
|
||||||
|
// function vectorFromObject(vec: { x: number; y: number; z: number }) {
|
||||||
|
// const { x, y, z } = vec
|
||||||
|
// const ideal = new Vector3(x, y, z)
|
||||||
|
// ideal.applyQuaternion($mesh.quaternion)
|
||||||
|
// ideal.add(new Vector3($mesh.position.x, $mesh.position.y, $mesh.position.z))
|
||||||
|
// return ideal
|
||||||
|
// }
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
// $cameraControls.moveTo(3, 5, 2, true)
|
||||||
|
// $cameraControls.setOrbitPoint(20, 20, 20)
|
||||||
|
$cameraControls.setLookAt(
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
2,
|
||||||
|
$mesh.position.x,
|
||||||
|
$mesh.position.y,
|
||||||
|
$mesh.position.z,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}, 8000)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
|
|
Loading…
Reference in a new issue