diff --git a/src/core/Group.js b/src/core/Group.js new file mode 100644 index 0000000..9b39f2f --- /dev/null +++ b/src/core/Group.js @@ -0,0 +1,38 @@ +import { Group } from 'three'; +import { inject } from 'vue'; +import useBindProp from '../use/useBindProp.js'; + +export default { + inject: ['three', 'scene'], + props: { + position: Object, + rotation: Object, + scale: Object, + }, + setup(props) { + const parent = inject('group', inject('scene')); + const group = new Group(); + useBindProp(props, 'position', group.position); + useBindProp(props, 'rotation', group.rotation); + useBindProp(props, 'scale', group.scale); + return { parent, group }; + }, + provide() { + return { + group: this.group, + }; + }, + created() { + this.parent.add(this.group); + }, + unmounted() { + this.parent.remove(this.group); + }, + render() { + if (this.$slots.default) { + return this.$slots.default(); + } + return []; + }, + __hmrId: 'Group', +}; diff --git a/src/core/index.js b/src/core/index.js index 7b4908d..10678ee 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -2,4 +2,5 @@ export { default as Renderer } from './Renderer.js'; export { default as OrthographicCamera } from './OrthographicCamera.js'; export { default as PerspectiveCamera } from './PerspectiveCamera.js'; export { default as Camera } from './PerspectiveCamera.js'; +export { default as Group } from './Group.js'; export { default as Scene } from './Scene.js'; diff --git a/src/lights/Light.js b/src/lights/Light.js index cf31580..0780d64 100644 --- a/src/lights/Light.js +++ b/src/lights/Light.js @@ -1,5 +1,5 @@ import { Color } from 'three'; -import { watch } from 'vue'; +import { inject, watch } from 'vue'; import { setFromProp } from '../tools.js'; import useBindProp from '../use/useBindProp.js'; @@ -21,6 +21,11 @@ export default { shadowMapSize: Object, position: Object, }, + // can't use setup because it will not be used in sub components + // setup() {}, + created() { + this.parent = inject('group', this.scene); + }, mounted() { useBindProp(this, 'position', this.light.position); @@ -43,11 +48,12 @@ export default { }); }); - this.scene.add(this.light); - if (this.light.target) this.scene.add(this.light.target); + this.parent.add(this.light); + if (this.light.target) this.parent.add(this.light.target); }, unmounted() { - this.scene.remove(this.light); + this.parent.remove(this.light); + if (this.light.target) this.parent.remove(this.light.target); }, render() { return []; diff --git a/src/meshes/Gem.js b/src/meshes/Gem.js index 0438320..74ceaec 100644 --- a/src/meshes/Gem.js +++ b/src/meshes/Gem.js @@ -26,7 +26,7 @@ export default { }, unmounted() { this.three.offBeforeRender(this.updateCubeRT); - if (this.meshBack) this.scene.remove(this.meshBack); + if (this.meshBack) this.parent.remove(this.meshBack); if (this.materialBack) this.materialBack.dispose(); }, methods: { @@ -34,7 +34,7 @@ export default { const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter }); this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT); useBindProp(this, 'position', this.cubeCamera.position); - this.scene.add(this.cubeCamera); + this.parent.add(this.cubeCamera); this.material.side = FrontSide; this.material.envMap = cubeRT.texture; @@ -58,7 +58,7 @@ export default { useBindProp(this, 'position', this.meshBack.position); useBindProp(this, 'rotation', this.meshBack.rotation); useBindProp(this, 'scale', this.meshBack.scale); - this.scene.add(this.meshBack); + this.parent.add(this.meshBack); }, updateCubeRT() { this.mesh.visible = false; diff --git a/src/meshes/InstancedMesh.js b/src/meshes/InstancedMesh.js index 541dd53..7068204 100644 --- a/src/meshes/InstancedMesh.js +++ b/src/meshes/InstancedMesh.js @@ -1,5 +1,5 @@ import { InstancedMesh } from 'three'; -import { watch } from 'vue'; +import { inject, watch } from 'vue'; import useBindProp from '../use/useBindProp.js'; export default { @@ -11,6 +11,9 @@ export default { castShadow: Boolean, receiveShadow: Boolean, }, + created() { + this.parent = inject('group', this.scene); + }, provide() { return { mesh: this, @@ -25,7 +28,7 @@ export default { this.initMesh(); }, unmounted() { - this.scene.remove(this.mesh); + this.parent.remove(this.mesh); }, methods: { initMesh() { @@ -48,7 +51,7 @@ export default { // this.mesh.material = this.three.materials[this.materialId]; // }); - this.scene.add(this.mesh); + this.parent.add(this.mesh); }, setGeometry(geometry) { this.geometry = geometry; diff --git a/src/meshes/Mesh.js b/src/meshes/Mesh.js index a095acd..a737591 100644 --- a/src/meshes/Mesh.js +++ b/src/meshes/Mesh.js @@ -1,5 +1,5 @@ import { Mesh } from 'three'; -import { watch } from 'vue'; +import { inject, watch } from 'vue'; import useBindProp from '../use/useBindProp.js'; export default { @@ -13,6 +13,11 @@ export default { castShadow: Boolean, receiveShadow: Boolean, }, + // can't use setup because it will not be used in sub components + // setup() {}, + created() { + this.parent = inject('group', this.scene); + }, provide() { return { mesh: this, @@ -24,7 +29,7 @@ export default { }, unmounted() { // console.log('Mesh unmounted'); - if (this.mesh) this.scene.remove(this.mesh); + if (this.mesh) this.parent.remove(this.mesh); if (this.geometry) this.geometry.dispose(); if (this.material && !this.materialId) this.material.dispose(); }, @@ -35,7 +40,7 @@ export default { } this.mesh = new Mesh(this.geometry, this.material); this.bindProps(); - this.scene.add(this.mesh); + this.parent.add(this.mesh); this.$emit('ready'); }, bindProps() { diff --git a/src/meshes/MirrorMesh.js b/src/meshes/MirrorMesh.js index 3e0d930..37ff08d 100644 --- a/src/meshes/MirrorMesh.js +++ b/src/meshes/MirrorMesh.js @@ -23,12 +23,13 @@ export default { }, unmounted() { this.three.offBeforeRender(this.updateCubeRT); + if (this.cubeCamera) this.parent.remove(this.cubeCamera); }, methods: { initMirrorMesh() { const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter }); this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT); - this.scene.add(this.cubeCamera); + this.parent.add(this.cubeCamera); this.material.envMap = cubeRT.texture; this.material.needsUpdate = true; diff --git a/src/meshes/RefractionMesh.js b/src/meshes/RefractionMesh.js index edc3ec2..6531c66 100644 --- a/src/meshes/RefractionMesh.js +++ b/src/meshes/RefractionMesh.js @@ -25,13 +25,14 @@ export default { }, unmounted() { this.three.offBeforeRender(this.updateCubeRT); + if (this.cubeCamera) this.parent.remove(this.cubeCamera); }, methods: { initMirrorMesh() { const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { mapping: CubeRefractionMapping, format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter }); this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT); useBindProp(this, 'position', this.cubeCamera.position); - this.scene.add(this.cubeCamera); + this.parent.add(this.cubeCamera); this.material.envMap = cubeRT.texture; this.material.refractionRatio = this.refractionRatio; diff --git a/src/meshes/Sprite.js b/src/meshes/Sprite.js index f17d757..d74f9ca 100644 --- a/src/meshes/Sprite.js +++ b/src/meshes/Sprite.js @@ -1,4 +1,5 @@ import { Sprite, SpriteMaterial, TextureLoader } from 'three'; +import { inject } from 'vue'; import useBindProp from '../use/useBindProp.js'; export default { @@ -9,6 +10,9 @@ export default { position: Object, scale: Object, }, + created() { + this.parent = inject('group', this.scene); + }, mounted() { this.texture = new TextureLoader().load(this.src, this.onLoaded); this.material = new SpriteMaterial({ map: this.texture }); @@ -17,13 +21,13 @@ export default { useBindProp(this, 'position', this.sprite.position); useBindProp(this, 'scale', this.sprite.scale); - this.scene.add(this.sprite); + this.parent.add(this.sprite); this.$emit('ready'); }, unmounted() { this.texture.dispose(); this.material.dispose(); - this.scene.remove(this.sprite); + this.parent.remove(this.sprite); }, methods: { onLoaded() { diff --git a/src/plugin.js b/src/plugin.js index 398efad..4b6a529 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -8,6 +8,7 @@ export const TroisJSVuePlugin = { 'PerspectiveCamera', 'Renderer', 'Scene', + 'Group', 'BoxGeometry', 'CircleGeometry',