diff --git a/src/lights/Light.js b/src/lights/Light.js index dfdb13e..430b34b 100644 --- a/src/lights/Light.js +++ b/src/lights/Light.js @@ -1,4 +1,5 @@ import { setFromProp } from '../tools.js'; +import useBindProp from '../use/useBindProp.js'; export default { inject: ['scene'], @@ -19,7 +20,7 @@ export default { position: Object, }, mounted() { - setFromProp(this.light.position, this.position); + useBindProp(this, 'position', this.light.position); if (this.light.shadow) { this.light.castShadow = this.castShadow; diff --git a/src/meshes/Mesh.js b/src/meshes/Mesh.js index 0641e8b..3704e56 100644 --- a/src/meshes/Mesh.js +++ b/src/meshes/Mesh.js @@ -1,6 +1,5 @@ -import { watch } from 'vue'; import { Mesh } from 'three'; -import { setFromProp } from '../tools.js'; +import useBindProp from '../use/useBindProp.js'; export default { inject: ['three', 'scene'], @@ -31,25 +30,16 @@ export default { this.material = this.three.materials[this.materialId]; } this.mesh = new Mesh(this.geometry, this.material); - this.updateMesh(); - this.scene.add(this.mesh); - this.addWatchers(); - this.$emit('ready'); - }, - addWatchers() { - ['position', 'rotation', 'scale'].forEach(p => { - watch(() => this[p], () => { - setFromProp(this.mesh[p], this[p]); - }, { deep: true }); - }); - }, - updateMesh() { - setFromProp(this.mesh.position, this.position); - setFromProp(this.mesh.rotation, this.rotation); - setFromProp(this.mesh.scale, this.scale); + useBindProp(this, 'position', this.mesh.position); + useBindProp(this, 'rotation', this.mesh.rotation); + useBindProp(this, 'scale', this.mesh.scale); + this.mesh.castShadow = this.castShadow; this.mesh.receiveShadow = this.receiveShadow; + + this.scene.add(this.mesh); + this.$emit('ready'); }, }, render() { diff --git a/src/meshes/Sprite.js b/src/meshes/Sprite.js new file mode 100644 index 0000000..200f403 --- /dev/null +++ b/src/meshes/Sprite.js @@ -0,0 +1,25 @@ +import { Sprite, SpriteMaterial, TextureLoader } from 'three'; +import useBindProp from '../use/useBindProp.js'; + +export default { + emits: ['ready', 'loaded'], + inject: ['three', 'scene'], + props: { + src: String, + position: Object, + }, + mounted() { + this.texture = new TextureLoader().load(this.src, () => { this.$emit('loaded'); }); + this.material = new SpriteMaterial({ map: this.texture }); + this.sprite = new Sprite(this.material); + useBindProp(this, 'position', this.sprite.position); + this.scene.add(this.sprite); + this.$emit('ready'); + }, + unmounted() { + this.texture.dispose(); + }, + render() { + return []; + }, +}; diff --git a/src/meshes/index.js b/src/meshes/index.js index 8f1be7e..ba0ef3f 100644 --- a/src/meshes/index.js +++ b/src/meshes/index.js @@ -5,3 +5,4 @@ export { default as Sphere } from './Sphere.js'; export { default as Text } from './Text.js'; export { default as InstancedMesh } from './InstancedMesh.js'; +export { default as Sprite } from './Sprite.js'; diff --git a/src/plugin.js b/src/plugin.js index d6f6f4b..212ce27 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -31,6 +31,7 @@ export const TroisJSVuePlugin = { 'Text', 'InstancedMesh', + 'Sprite', 'BokehPass', 'EffectComposer', diff --git a/src/use/useBindProp.js b/src/use/useBindProp.js new file mode 100644 index 0000000..d5972fd --- /dev/null +++ b/src/use/useBindProp.js @@ -0,0 +1,10 @@ +import { toRef, watch } from 'vue'; +import { setFromProp } from '../tools.js'; + +export default function useBindProp(comp, prop, object) { + const ref = toRef(comp, prop); + setFromProp(object, ref.value); + watch(ref, () => { + setFromProp(object, ref.value); + }, { deep: true }); +};