mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
wip
This commit is contained in:
parent
3e9138d1db
commit
04890fc2fb
@ -8,16 +8,17 @@ import {
|
|||||||
ShaderMaterial,
|
ShaderMaterial,
|
||||||
Uniform,
|
Uniform,
|
||||||
Vector2,
|
Vector2,
|
||||||
|
WebGLRenderer,
|
||||||
WebGLRenderTarget,
|
WebGLRenderTarget,
|
||||||
} from 'three';
|
} from 'three'
|
||||||
|
|
||||||
// shaders from https://github.com/evanw/webgl-water
|
// shaders from https://github.com/evanw/webgl-water
|
||||||
function LiquidEffect(renderer) {
|
function LiquidEffect(renderer) {
|
||||||
this.renderer = renderer;
|
this.renderer = renderer
|
||||||
this.width = 512;
|
this.width = 512
|
||||||
this.height = 512;
|
this.height = 512
|
||||||
// this.delta = new Vector2(this.width / Math.pow(width, 2), this.height / Math.pow(height, 2));
|
// this.delta = new Vector2(this.width / Math.pow(width, 2), this.height / Math.pow(height, 2));
|
||||||
this.delta = new Vector2(1 / this.width, 1 / this.height);
|
this.delta = new Vector2(1 / this.width, 1 / this.height)
|
||||||
|
|
||||||
const targetOptions = {
|
const targetOptions = {
|
||||||
minFilter: NearestFilter,
|
minFilter: NearestFilter,
|
||||||
@ -25,14 +26,14 @@ function LiquidEffect(renderer) {
|
|||||||
type: FloatType,
|
type: FloatType,
|
||||||
format: RGBAFormat,
|
format: RGBAFormat,
|
||||||
depthBuffer: false,
|
depthBuffer: false,
|
||||||
};
|
}
|
||||||
|
|
||||||
this.hMap = new WebGLRenderTarget(this.width, this.height, targetOptions);
|
this.hMap = new WebGLRenderTarget(this.width, this.height, targetOptions)
|
||||||
this.hMap1 = new WebGLRenderTarget(this.width, this.height, targetOptions);
|
this.hMap1 = new WebGLRenderTarget(this.width, this.height, targetOptions)
|
||||||
this.fsQuad = new FullScreenQuad();
|
this.fsQuad = new FullScreenQuad()
|
||||||
|
|
||||||
this.initShaders();
|
this.initShaders()
|
||||||
};
|
}
|
||||||
|
|
||||||
LiquidEffect.prototype.initShaders = function () {
|
LiquidEffect.prototype.initShaders = function () {
|
||||||
const defaultVertexShader = `
|
const defaultVertexShader = `
|
||||||
@ -41,7 +42,7 @@ LiquidEffect.prototype.initShaders = function () {
|
|||||||
vUv = uv;
|
vUv = uv;
|
||||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||||
}
|
}
|
||||||
`;
|
`
|
||||||
|
|
||||||
this.copyMat = new ShaderMaterial({
|
this.copyMat = new ShaderMaterial({
|
||||||
uniforms: { tDiffuse: { value: null } },
|
uniforms: { tDiffuse: { value: null } },
|
||||||
@ -53,7 +54,7 @@ LiquidEffect.prototype.initShaders = function () {
|
|||||||
gl_FragColor = texture2D(tDiffuse, vUv);
|
gl_FragColor = texture2D(tDiffuse, vUv);
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
});
|
})
|
||||||
|
|
||||||
this.updateMat = new ShaderMaterial({
|
this.updateMat = new ShaderMaterial({
|
||||||
uniforms: {
|
uniforms: {
|
||||||
@ -83,7 +84,7 @@ LiquidEffect.prototype.initShaders = function () {
|
|||||||
gl_FragColor = texel;
|
gl_FragColor = texel;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
});
|
})
|
||||||
|
|
||||||
this.normalsMat = new ShaderMaterial({
|
this.normalsMat = new ShaderMaterial({
|
||||||
uniforms: {
|
uniforms: {
|
||||||
@ -103,7 +104,7 @@ LiquidEffect.prototype.initShaders = function () {
|
|||||||
gl_FragColor = texel;
|
gl_FragColor = texel;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
});
|
})
|
||||||
|
|
||||||
this.dropMat = new ShaderMaterial({
|
this.dropMat = new ShaderMaterial({
|
||||||
uniforms: {
|
uniforms: {
|
||||||
@ -129,35 +130,35 @@ LiquidEffect.prototype.initShaders = function () {
|
|||||||
gl_FragColor = texel;
|
gl_FragColor = texel;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
LiquidEffect.prototype.update = function () {
|
LiquidEffect.prototype.update = function () {
|
||||||
this.updateHMap();
|
this.updateHMap()
|
||||||
// this.updateHMap();
|
// this.updateHMap();
|
||||||
this.updateHMapNormals();
|
this.updateHMapNormals()
|
||||||
};
|
}
|
||||||
|
|
||||||
LiquidEffect.prototype.updateHMap = function () {
|
LiquidEffect.prototype.updateHMap = function () {
|
||||||
this.updateMat.uniforms.tDiffuse.value = this.hMap.texture;
|
this.updateMat.uniforms.tDiffuse.value = this.hMap.texture
|
||||||
this.renderShaderMat(this.updateMat, this.hMap1);
|
this.renderShaderMat(this.updateMat, this.hMap1)
|
||||||
this.swapBuffers();
|
this.swapBuffers()
|
||||||
};
|
}
|
||||||
|
|
||||||
LiquidEffect.prototype.updateHMapNormals = function () {
|
LiquidEffect.prototype.updateHMapNormals = function () {
|
||||||
this.normalsMat.uniforms.tDiffuse.value = this.hMap.texture;
|
this.normalsMat.uniforms.tDiffuse.value = this.hMap.texture
|
||||||
this.renderShaderMat(this.normalsMat, this.hMap1);
|
this.renderShaderMat(this.normalsMat, this.hMap1)
|
||||||
this.swapBuffers();
|
this.swapBuffers()
|
||||||
};
|
}
|
||||||
|
|
||||||
LiquidEffect.prototype.addDrop = function (x, y, radius, strength) {
|
LiquidEffect.prototype.addDrop = function (x, y, radius, strength) {
|
||||||
this.dropMat.uniforms.tDiffuse.value = this.hMap.texture;
|
this.dropMat.uniforms.tDiffuse.value = this.hMap.texture
|
||||||
this.dropMat.uniforms.center.value.set(x, y);
|
this.dropMat.uniforms.center.value.set(x, y)
|
||||||
this.dropMat.uniforms.radius.value = radius;
|
this.dropMat.uniforms.radius.value = radius
|
||||||
this.dropMat.uniforms.strength.value = strength;
|
this.dropMat.uniforms.strength.value = strength
|
||||||
this.renderShaderMat(this.dropMat, this.hMap1);
|
this.renderShaderMat(this.dropMat, this.hMap1)
|
||||||
this.swapBuffers();
|
this.swapBuffers()
|
||||||
};
|
}
|
||||||
|
|
||||||
// LiquidEffect.prototype.renderBuffer = function (buffer, target) {
|
// LiquidEffect.prototype.renderBuffer = function (buffer, target) {
|
||||||
// this.copyMat.uniforms.tDiffuse.value = buffer.texture;
|
// this.copyMat.uniforms.tDiffuse.value = buffer.texture;
|
||||||
@ -165,40 +166,40 @@ LiquidEffect.prototype.addDrop = function (x, y, radius, strength) {
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
LiquidEffect.prototype.renderShaderMat = function (mat, target) {
|
LiquidEffect.prototype.renderShaderMat = function (mat, target) {
|
||||||
this.fsQuad.material = mat;
|
this.fsQuad.material = mat
|
||||||
const oldTarget = this.renderer.getRenderTarget();
|
const oldTarget = this.renderer.getRenderTarget()
|
||||||
this.renderer.setRenderTarget(target);
|
this.renderer.setRenderTarget(target)
|
||||||
this.fsQuad.render(this.renderer);
|
this.fsQuad.render(this.renderer)
|
||||||
this.renderer.setRenderTarget(oldTarget);
|
this.renderer.setRenderTarget(oldTarget)
|
||||||
};
|
}
|
||||||
|
|
||||||
LiquidEffect.prototype.swapBuffers = function () {
|
LiquidEffect.prototype.swapBuffers = function () {
|
||||||
const temp = this.hMap;
|
const temp = this.hMap
|
||||||
this.hMap = this.hMap1;
|
this.hMap = this.hMap1
|
||||||
this.hMap1 = temp;
|
this.hMap1 = temp
|
||||||
};
|
}
|
||||||
|
|
||||||
// from https://threejs.org/examples/js/postprocessing/EffectComposer.js
|
// from https://threejs.org/examples/js/postprocessing/EffectComposer.js
|
||||||
const FullScreenQuad = (function () {
|
const FullScreenQuad = (function () {
|
||||||
const camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
const camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1)
|
||||||
const geometry = new PlaneGeometry(2, 2);
|
const geometry = new PlaneGeometry(2, 2)
|
||||||
|
|
||||||
const FullScreenQuad = function (material) {
|
const FullScreenQuad = function (material) {
|
||||||
this._mesh = new Mesh(geometry, material);
|
this._mesh = new Mesh(geometry, material)
|
||||||
};
|
}
|
||||||
|
|
||||||
Object.defineProperty(FullScreenQuad.prototype, 'material', {
|
Object.defineProperty(FullScreenQuad.prototype, 'material', {
|
||||||
get: function () { return this._mesh.material; },
|
get: function () { return this._mesh.material },
|
||||||
set: function (value) { this._mesh.material = value; },
|
set: function (value) { this._mesh.material = value },
|
||||||
});
|
})
|
||||||
|
|
||||||
Object.assign(FullScreenQuad.prototype, {
|
Object.assign(FullScreenQuad.prototype, {
|
||||||
render: function (renderer) {
|
render: function (renderer) {
|
||||||
renderer.render(this._mesh, camera);
|
renderer.render(this._mesh, camera)
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
return FullScreenQuad;
|
return FullScreenQuad
|
||||||
})();
|
})()
|
||||||
|
|
||||||
export default LiquidEffect;
|
export default LiquidEffect
|
||||||
|
@ -16,7 +16,7 @@ export default defineComponent({
|
|||||||
roughness: { type: Number, default: 0.25 },
|
roughness: { type: Number, default: 0.25 },
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.liquidEffect = new LiquidEffect(this.three.renderer);
|
this.liquidEffect = new LiquidEffect(this.renderer.renderer);
|
||||||
this.renderer.onMounted(() => {
|
this.renderer.onMounted(() => {
|
||||||
this.liquidEffect.renderer = this.renderer.renderer;
|
this.liquidEffect.renderer = this.renderer.renderer;
|
||||||
this.renderer.onBeforeRender(this.update);
|
this.renderer.onBeforeRender(this.update);
|
||||||
|
@ -64,7 +64,7 @@ export default defineComponent({
|
|||||||
updateCubeRT() {
|
updateCubeRT() {
|
||||||
this.mesh.visible = false;
|
this.mesh.visible = false;
|
||||||
this.meshBack.visible = false;
|
this.meshBack.visible = false;
|
||||||
this.cubeCamera.update(this.three.renderer, this.scene);
|
this.cubeCamera.update(this.renderer.renderer, this.scene);
|
||||||
this.mesh.visible = true;
|
this.mesh.visible = true;
|
||||||
this.meshBack.visible = true;
|
this.meshBack.visible = true;
|
||||||
},
|
},
|
||||||
|
@ -35,7 +35,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
updateCubeRT() {
|
updateCubeRT() {
|
||||||
this.mesh.visible = false;
|
this.mesh.visible = false;
|
||||||
this.cubeCamera.update(this.three.renderer, this.scene);
|
this.cubeCamera.update(this.renderer.renderer, this.scene);
|
||||||
this.mesh.visible = true;
|
this.mesh.visible = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -40,7 +40,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
updateCubeRT() {
|
updateCubeRT() {
|
||||||
this.mesh.visible = false;
|
this.mesh.visible = false;
|
||||||
this.cubeCamera.update(this.three.renderer, this.scene);
|
this.cubeCamera.update(this.renderer.renderer, this.scene);
|
||||||
this.mesh.visible = true;
|
this.mesh.visible = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -117,7 +117,7 @@ export default defineComponent({
|
|||||||
this.renderMat(this.normMat, this.normRT);
|
this.renderMat(this.normMat, this.normRT);
|
||||||
},
|
},
|
||||||
renderMat(mat, target) {
|
renderMat(mat, target) {
|
||||||
const renderer = this.three.renderer;
|
const renderer = this.renderer.renderer;
|
||||||
this.fsQuad.material = mat;
|
this.fsQuad.material = mat;
|
||||||
const oldTarget = renderer.getRenderTarget();
|
const oldTarget = renderer.getRenderTarget();
|
||||||
renderer.setRenderTarget(target);
|
renderer.setRenderTarget(target);
|
||||||
|
@ -45,7 +45,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
this.loader.dispose();
|
this.loader.dispose();
|
||||||
const domElement = this.three.renderer.domElement;
|
const domElement = this.renderer.renderer.domElement;
|
||||||
domElement.removeEventListener('click', this.onClick);
|
domElement.removeEventListener('click', this.onClick);
|
||||||
domElement.removeEventListener('wheel', this.onWheel);
|
domElement.removeEventListener('wheel', this.onWheel);
|
||||||
document.removeEventListener('keyup', this.onKeyup);
|
document.removeEventListener('keyup', this.onKeyup);
|
||||||
@ -65,26 +65,26 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const domElement = this.three.renderer.domElement;
|
const domElement = this.renderer.renderer.domElement;
|
||||||
if (this.events.click) domElement.addEventListener('click', this.onClick);
|
if (this.events.click) domElement.addEventListener('click', this.onClick);
|
||||||
if (this.events.wheel) domElement.addEventListener('wheel', this.onWheel);
|
if (this.events.wheel) domElement.addEventListener('wheel', this.onWheel);
|
||||||
if (this.events.keyup) document.addEventListener('keyup', this.onKeyup);
|
if (this.events.keyup) document.addEventListener('keyup', this.onKeyup);
|
||||||
this.renderer.onBeforeRender(this.updateProgress);
|
this.renderer.onBeforeRender(this.updateProgress);
|
||||||
this.renderer.onAfterResize(this.onResize);
|
this.renderer.onResize(this.onResize);
|
||||||
},
|
},
|
||||||
initScene() {
|
initScene() {
|
||||||
const renderer = this.three.renderer;
|
const renderer = this.renderer.renderer;
|
||||||
const scene = this.$refs.scene.scene;
|
const scene = this.$refs.scene.scene;
|
||||||
|
|
||||||
this.plane1 = new AnimatedPlane({
|
this.plane1 = new AnimatedPlane({
|
||||||
renderer, screen: this.three.size,
|
renderer, screen: this.renderer.size,
|
||||||
size: 10,
|
size: 10,
|
||||||
anim: 1,
|
anim: 1,
|
||||||
texture: this.loader.textures[0],
|
texture: this.loader.textures[0],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.plane2 = new AnimatedPlane({
|
this.plane2 = new AnimatedPlane({
|
||||||
renderer, screen: this.three.size,
|
renderer, screen: this.renderer.size,
|
||||||
size: 10,
|
size: 10,
|
||||||
anim: 2,
|
anim: 2,
|
||||||
texture: this.loader.textures[1],
|
texture: this.loader.textures[1],
|
||||||
@ -109,7 +109,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClick(e) {
|
onClick(e) {
|
||||||
if (e.clientY < this.three.size.height / 2) {
|
if (e.clientY < this.renderer.size.height / 2) {
|
||||||
this.navPrevious();
|
this.navPrevious();
|
||||||
} else {
|
} else {
|
||||||
this.navNext();
|
this.navNext();
|
||||||
|
@ -47,7 +47,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
this.loader.dispose();
|
this.loader.dispose();
|
||||||
const domElement = this.three.renderer.domElement;
|
const domElement = this.renderer.renderer.domElement;
|
||||||
domElement.removeEventListener('click', this.onClick);
|
domElement.removeEventListener('click', this.onClick);
|
||||||
domElement.removeEventListener('wheel', this.onWheel);
|
domElement.removeEventListener('wheel', this.onWheel);
|
||||||
document.removeEventListener('keyup', this.onKeyup);
|
document.removeEventListener('keyup', this.onKeyup);
|
||||||
@ -66,19 +66,19 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const domElement = this.three.renderer.domElement;
|
const domElement = this.renderer.renderer.domElement;
|
||||||
if (this.events.click) domElement.addEventListener('click', this.onClick);
|
if (this.events.click) domElement.addEventListener('click', this.onClick);
|
||||||
if (this.events.wheel) domElement.addEventListener('wheel', this.onWheel);
|
if (this.events.wheel) domElement.addEventListener('wheel', this.onWheel);
|
||||||
if (this.events.keyup) document.addEventListener('keyup', this.onKeyup);
|
if (this.events.keyup) document.addEventListener('keyup', this.onKeyup);
|
||||||
this.renderer.onBeforeRender(this.animate);
|
this.renderer.onBeforeRender(this.animate);
|
||||||
this.renderer.onAfterResize(this.onResize);
|
this.renderer.onResize(this.onResize);
|
||||||
},
|
},
|
||||||
initScene() {
|
initScene() {
|
||||||
const scene = this.$refs.scene.scene;
|
const scene = this.$refs.scene.scene;
|
||||||
|
|
||||||
this.image1 = new ZoomBlurImage(this.three);
|
this.image1 = new ZoomBlurImage(this.renderer);
|
||||||
this.image1.setMap(this.loader.textures[0]);
|
this.image1.setMap(this.loader.textures[0]);
|
||||||
this.image2 = new ZoomBlurImage(this.three);
|
this.image2 = new ZoomBlurImage(this.renderer);
|
||||||
this.image2.setMap(this.loader.textures[1]);
|
this.image2.setMap(this.loader.textures[1]);
|
||||||
this.setImagesProgress(0);
|
this.setImagesProgress(0);
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ export default defineComponent({
|
|||||||
scene.add(this.image2.mesh);
|
scene.add(this.image2.mesh);
|
||||||
},
|
},
|
||||||
animate() {
|
animate() {
|
||||||
const { positionN } = this.three.pointer;
|
const { positionN } = this.renderer.pointer;
|
||||||
this.center.copy(positionN).divideScalar(2).addScalar(0.5);
|
this.center.copy(positionN).divideScalar(2).addScalar(0.5);
|
||||||
lerpv2(this.image1.uCenter.value, this.center, 0.1);
|
lerpv2(this.image1.uCenter.value, this.center, 0.1);
|
||||||
lerpv2(this.image2.uCenter.value, this.center, 0.1);
|
lerpv2(this.image2.uCenter.value, this.center, 0.1);
|
||||||
@ -106,7 +106,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClick(e) {
|
onClick(e) {
|
||||||
if (e.clientY < this.three.size.height / 2) {
|
if (e.clientY < this.renderer.size.height / 2) {
|
||||||
this.navPrevious();
|
this.navPrevious();
|
||||||
} else {
|
} else {
|
||||||
this.navNext();
|
this.navNext();
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
Vector2,
|
Vector2,
|
||||||
} from 'three';
|
} from 'three';
|
||||||
|
|
||||||
export default function ZoomBlurImage(three) {
|
export default function ZoomBlurImage(renderer) {
|
||||||
let geometry, material, mesh;
|
let geometry, material, mesh;
|
||||||
|
|
||||||
const uMap = { value: null };
|
const uMap = { value: null };
|
||||||
@ -94,7 +94,7 @@ export default function ZoomBlurImage(three) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateUV() {
|
function updateUV() {
|
||||||
const ratio = three.size.ratio;
|
const ratio = renderer.size.ratio;
|
||||||
const iRatio = uMap.value.image.width / uMap.value.image.height;
|
const iRatio = uMap.value.image.width / uMap.value.image.height;
|
||||||
uUVOffset.value.set(0, 0);
|
uUVOffset.value.set(0, 0);
|
||||||
uUVScale.value.set(1, 1);
|
uUVScale.value.set(1, 1);
|
||||||
|
@ -25,7 +25,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const loader = new GLTFLoader();
|
const loader = new GLTFLoader();
|
||||||
loader.load(this.src, (gltf) => {
|
loader.load(this.src, (gltf) => {
|
||||||
this.renderer.three.scene.add(gltf.scene);
|
this.renderer.scene.add(gltf.scene);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { defineComponent, inject } from 'vue'
|
import { defineComponent, inject } from 'vue'
|
||||||
import { ThreeInterface } from './useThree'
|
import { RendererInterface } from './Renderer'
|
||||||
// import Object3D from './Object3D'
|
// import Object3D from './Object3D'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -8,13 +8,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
// don't work with typescript, bug ?
|
// don't work with typescript, bug ?
|
||||||
// but works in sub components (injection, not typescript)
|
// but works in sub components (injection, not typescript)
|
||||||
inject: ['three'],
|
inject: ['renderer'],
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
// this works with typescript in sub component
|
// this works with typescript in sub component
|
||||||
// but setup is not called
|
// but setup is not called
|
||||||
const three = inject('three') as ThreeInterface
|
const renderer = inject('renderer') as RendererInterface
|
||||||
return { three }
|
return { renderer }
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
return this.$slots.default ? this.$slots.default() : []
|
return this.$slots.default ? this.$slots.default() : []
|
||||||
|
@ -34,7 +34,7 @@ export default defineComponent({
|
|||||||
return { camera }
|
return { camera }
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.three.camera = this.camera
|
this.renderer.camera = this.camera
|
||||||
},
|
},
|
||||||
__hmrId: 'OrthographicCamera',
|
__hmrId: 'OrthographicCamera',
|
||||||
})
|
})
|
||||||
|
@ -36,7 +36,7 @@ export default defineComponent({
|
|||||||
return { camera }
|
return { camera }
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.three.camera = this.camera
|
this.renderer.camera = this.camera
|
||||||
},
|
},
|
||||||
__hmrId: 'PerspectiveCamera',
|
__hmrId: 'PerspectiveCamera',
|
||||||
})
|
})
|
||||||
|
@ -2,14 +2,12 @@ import { Object3D } from 'three'
|
|||||||
import { defineComponent, inject, PropType } from 'vue'
|
import { defineComponent, inject, PropType } from 'vue'
|
||||||
import usePointer, { IntersectObject, PointerInterface, PointerIntersectCallbackType } from './usePointer'
|
import usePointer, { IntersectObject, PointerInterface, PointerIntersectCallbackType } from './usePointer'
|
||||||
import { RendererInterface } from './Renderer'
|
import { RendererInterface } from './Renderer'
|
||||||
import { ThreeInterface } from './useThree'
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
const emptyCallBack: PointerIntersectCallbackType = () => {}
|
const emptyCallBack: PointerIntersectCallbackType = () => {}
|
||||||
|
|
||||||
interface RaycasterSetupInterface {
|
interface RaycasterSetupInterface {
|
||||||
renderer: RendererInterface
|
renderer: RendererInterface
|
||||||
three: ThreeInterface
|
|
||||||
pointer?: PointerInterface
|
pointer?: PointerInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,22 +23,21 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
setup(): RaycasterSetupInterface {
|
setup(): RaycasterSetupInterface {
|
||||||
const renderer = inject('renderer') as RendererInterface
|
const renderer = inject('renderer') as RendererInterface
|
||||||
const three = inject('three') as ThreeInterface
|
return { renderer }
|
||||||
return { renderer, three }
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.renderer.onMounted(() => {
|
this.renderer.onMounted(() => {
|
||||||
if (!this.three.camera) return
|
if (!this.renderer.camera) return
|
||||||
|
|
||||||
this.pointer = usePointer({
|
this.pointer = usePointer({
|
||||||
camera: this.three.camera,
|
camera: this.renderer.camera,
|
||||||
domElement: this.renderer.canvas,
|
domElement: this.renderer.canvas,
|
||||||
intersectObjects: this.getIntersectObjects(),
|
intersectObjects: this.getIntersectObjects(),
|
||||||
onIntersectEnter: (<PointerIntersectCallbackType> this.onPointerEnter),
|
onIntersectEnter: this.onPointerEnter,
|
||||||
onIntersectOver: (<PointerIntersectCallbackType> this.onPointerOver),
|
onIntersectOver: this.onPointerOver,
|
||||||
onIntersectMove: (<PointerIntersectCallbackType> this.onPointerMove),
|
onIntersectMove: this.onPointerMove,
|
||||||
onIntersectLeave: (<PointerIntersectCallbackType> this.onPointerLeave),
|
onIntersectLeave: this.onPointerLeave,
|
||||||
onIntersectClick: (<PointerIntersectCallbackType> this.onClick),
|
onIntersectClick: this.onClick,
|
||||||
})
|
})
|
||||||
this.pointer.addListeners()
|
this.pointer.addListeners()
|
||||||
|
|
||||||
@ -57,8 +54,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getIntersectObjects() {
|
getIntersectObjects() {
|
||||||
if (this.three.scene) {
|
if (this.renderer.scene) {
|
||||||
const children = this.three.scene.children.filter((c: Object3D) => ['Mesh', 'InstancedMesh'].includes(c.type))
|
const children = this.renderer.scene.children.filter((c: Object3D) => ['Mesh', 'InstancedMesh'].includes(c.type))
|
||||||
return children as IntersectObject[]
|
return children as IntersectObject[]
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
/* eslint-disable no-use-before-define */
|
/* eslint-disable no-use-before-define */
|
||||||
import { WebGLRenderer } from 'three'
|
import { Camera, Scene, WebGLRenderer } from 'three'
|
||||||
|
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
|
||||||
import { defineComponent, PropType } from 'vue'
|
import { defineComponent, PropType } from 'vue'
|
||||||
import useThree, { SizeInterface, ThreeConfigInterface, ThreeInterface } from './useThree'
|
import useThree, { SizeInterface, ThreeConfigInterface, ThreeInterface } from './useThree'
|
||||||
|
|
||||||
type CallbackType<T> = (event?: T) => void
|
type CallbackType<T> = (event: T) => void
|
||||||
|
|
||||||
// type EventType = 'init' | 'mounted' | 'beforerender' | 'afterrender' | 'resize'
|
// type EventType = 'init' | 'mounted' | 'beforerender' | 'afterrender' | 'resize'
|
||||||
|
|
||||||
interface EventInterface {
|
export interface EventInterface {
|
||||||
type: 'init' | 'mounted'
|
type: 'init' | 'mounted'
|
||||||
renderer: RendererInterface
|
renderer: RendererInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RenderEventInterface {
|
export interface RenderEventInterface {
|
||||||
type: 'beforerender' | 'afterrender'
|
type: 'beforerender' | 'afterrender'
|
||||||
renderer: RendererInterface
|
renderer: RendererInterface
|
||||||
time: number
|
time: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ResizeEventInterface {
|
export interface ResizeEventInterface {
|
||||||
type: 'resize'
|
type: 'resize'
|
||||||
renderer: RendererInterface
|
renderer: RendererInterface
|
||||||
size: SizeInterface
|
size: SizeInterface
|
||||||
@ -66,6 +67,10 @@ interface RendererSetupInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface RendererInterface extends RendererSetupInterface {
|
export interface RendererInterface extends RendererSetupInterface {
|
||||||
|
scene?: Scene
|
||||||
|
camera?: Camera
|
||||||
|
composer?: EffectComposer
|
||||||
|
|
||||||
onInit(cb: InitCallbackType): void
|
onInit(cb: InitCallbackType): void
|
||||||
onMounted(cb: MountedCallbackType): void
|
onMounted(cb: MountedCallbackType): void
|
||||||
|
|
||||||
@ -135,6 +140,20 @@ export default defineComponent({
|
|||||||
resizeCallbacks,
|
resizeCallbacks,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
camera: {
|
||||||
|
get: function(): Camera | undefined { return this.three.camera },
|
||||||
|
set: function(camera: Camera): void { this.three.camera = camera },
|
||||||
|
},
|
||||||
|
scene: {
|
||||||
|
get: function(): Scene | undefined { return this.three.scene },
|
||||||
|
set: function(scene: Scene): void { this.three.scene = scene },
|
||||||
|
},
|
||||||
|
composer: {
|
||||||
|
get: function(): EffectComposer | undefined { return this.three.composer },
|
||||||
|
set: function(composer: EffectComposer): void { this.three.composer = composer },
|
||||||
|
},
|
||||||
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
renderer: this,
|
renderer: this,
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
import { defineComponent, inject, watch } from 'vue'
|
import { defineComponent, inject, watch } from 'vue'
|
||||||
import { Scene, Color, Object3D } from 'three'
|
import { Scene, Color, Object3D } from 'three'
|
||||||
import { ThreeInterface } from './useThree'
|
import { RendererInterface } from './Renderer'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Scene',
|
name: 'Scene',
|
||||||
// inject: ['three'],
|
|
||||||
props: {
|
props: {
|
||||||
// id: String,
|
// id: String,
|
||||||
background: [String, Number],
|
background: [String, Number],
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const three = inject('three') as ThreeInterface
|
const renderer = inject('renderer') as RendererInterface
|
||||||
const scene = new Scene()
|
const scene = new Scene()
|
||||||
if (props.background) {
|
if (props.background) {
|
||||||
scene.background = new Color(props.background)
|
scene.background = new Color(props.background)
|
||||||
}
|
}
|
||||||
watch(() => props.background, (value) => { if (scene.background instanceof Color && value) scene.background.set(value) })
|
watch(() => props.background, (value) => { if (scene.background instanceof Color && value) scene.background.set(value) })
|
||||||
return { three, scene }
|
return { renderer, scene }
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
@ -24,8 +23,8 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (!this.three.scene) {
|
if (!this.renderer.scene) {
|
||||||
this.three.scene = this.scene
|
this.renderer.scene = this.scene
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -12,11 +12,11 @@ export default defineComponent({
|
|||||||
extends: EffectPass,
|
extends: EffectPass,
|
||||||
props,
|
props,
|
||||||
created() {
|
created() {
|
||||||
if (!this.three.scene) {
|
if (!this.renderer.scene) {
|
||||||
console.error('Missing Scene')
|
console.error('Missing Scene')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!this.three.camera) {
|
if (!this.renderer.camera) {
|
||||||
console.error('Missing Camera')
|
console.error('Missing Camera')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -25,11 +25,11 @@ export default defineComponent({
|
|||||||
focus: this.focus,
|
focus: this.focus,
|
||||||
aperture: this.aperture,
|
aperture: this.aperture,
|
||||||
maxblur: this.maxblur,
|
maxblur: this.maxblur,
|
||||||
width: this.three.size.width,
|
width: this.renderer.size.width,
|
||||||
height: this.three.size.height,
|
height: this.renderer.size.height,
|
||||||
}
|
}
|
||||||
|
|
||||||
const pass = new BokehPass(this.three.scene, this.three.camera, params)
|
const pass = new BokehPass(this.renderer.scene, this.renderer.camera, params)
|
||||||
|
|
||||||
Object.keys(props).forEach(p => {
|
Object.keys(props).forEach(p => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -28,7 +28,7 @@ export default defineComponent({
|
|||||||
created() {
|
created() {
|
||||||
const composer = new EffectComposer(this.renderer.renderer)
|
const composer = new EffectComposer(this.renderer.renderer)
|
||||||
this.composer = composer
|
this.composer = composer
|
||||||
this.renderer.three.composer = composer
|
this.renderer.composer = composer
|
||||||
|
|
||||||
// this.renderer.onInit(() => {
|
// this.renderer.onInit(() => {
|
||||||
this.renderer.addListener('init', () => {
|
this.renderer.addListener('init', () => {
|
||||||
|
@ -9,7 +9,7 @@ export default defineComponent({
|
|||||||
created() {
|
created() {
|
||||||
const pass = new ShaderPass(FXAAShader)
|
const pass = new ShaderPass(FXAAShader)
|
||||||
|
|
||||||
// resize will be called in three init
|
// resize will be first called in renderer init
|
||||||
this.renderer.addListener('resize', this.resize)
|
this.renderer.addListener('resize', this.resize)
|
||||||
|
|
||||||
this.initEffectPass(pass)
|
this.initEffectPass(pass)
|
||||||
|
@ -15,7 +15,7 @@ export default defineComponent({
|
|||||||
extends: EffectPass,
|
extends: EffectPass,
|
||||||
props,
|
props,
|
||||||
created() {
|
created() {
|
||||||
const pass = new HalftonePass(this.three.size.width, this.three.size.height, {})
|
const pass = new HalftonePass(this.renderer.size.width, this.renderer.size.height, {})
|
||||||
|
|
||||||
Object.keys(props).forEach(p => {
|
Object.keys(props).forEach(p => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -5,15 +5,15 @@ import EffectPass from './EffectPass'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
extends: EffectPass,
|
extends: EffectPass,
|
||||||
created() {
|
created() {
|
||||||
if (!this.three.scene) {
|
if (!this.renderer.scene) {
|
||||||
console.error('Missing Scene')
|
console.error('Missing Scene')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!this.three.camera) {
|
if (!this.renderer.camera) {
|
||||||
console.error('Missing Camera')
|
console.error('Missing Camera')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const pass = new RenderPass(this.three.scene, this.three.camera)
|
const pass = new RenderPass(this.renderer.scene, this.renderer.camera)
|
||||||
this.initEffectPass(pass)
|
this.initEffectPass(pass)
|
||||||
},
|
},
|
||||||
__hmrId: 'RenderPass',
|
__hmrId: 'RenderPass',
|
||||||
|
@ -5,8 +5,7 @@ import EffectPass from './EffectPass'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
extends: EffectPass,
|
extends: EffectPass,
|
||||||
created() {
|
created() {
|
||||||
// three size is not set yet, but this pass will be resized by effect composer
|
const pass = new SMAAPass(this.renderer.size.width, this.renderer.size.height)
|
||||||
const pass = new SMAAPass(this.three.size.width, this.three.size.height)
|
|
||||||
this.initEffectPass(pass)
|
this.initEffectPass(pass)
|
||||||
},
|
},
|
||||||
__hmrId: 'SMAAPass',
|
__hmrId: 'SMAAPass',
|
||||||
|
@ -11,20 +11,20 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (!this.three.scene) {
|
if (!this.renderer.scene) {
|
||||||
console.error('Missing Scene')
|
console.error('Missing Scene')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!this.three.camera) {
|
if (!this.renderer.camera) {
|
||||||
console.error('Missing Camera')
|
console.error('Missing Camera')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const pass = new SSAOPass(
|
const pass = new SSAOPass(
|
||||||
this.three.scene,
|
this.renderer.scene,
|
||||||
this.three.camera,
|
this.renderer.camera,
|
||||||
this.three.size.width,
|
this.renderer.size.width,
|
||||||
this.three.size.height
|
this.renderer.size.height
|
||||||
)
|
)
|
||||||
|
|
||||||
Object.keys(this.options).forEach(key => {
|
Object.keys(this.options).forEach(key => {
|
||||||
|
@ -13,7 +13,7 @@ export default defineComponent({
|
|||||||
extends: EffectPass,
|
extends: EffectPass,
|
||||||
props,
|
props,
|
||||||
created() {
|
created() {
|
||||||
const size = new Vector2(this.three.size.width, this.three.size.height)
|
const size = new Vector2(this.renderer.size.width, this.renderer.size.height)
|
||||||
const pass = new UnrealBloomPass(size, this.strength, this.radius, this.threshold)
|
const pass = new UnrealBloomPass(size, this.strength, this.radius, this.threshold)
|
||||||
|
|
||||||
Object.keys(props).forEach(p => {
|
Object.keys(props).forEach(p => {
|
||||||
|
@ -71,6 +71,7 @@ const Geometry = defineComponent({
|
|||||||
|
|
||||||
export default Geometry
|
export default Geometry
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export function geometryComponent(name, props, createGeometry) {
|
export function geometryComponent(name, props, createGeometry) {
|
||||||
return defineComponent({
|
return defineComponent({
|
||||||
name,
|
name,
|
||||||
|
@ -32,7 +32,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
// update points (without using prop, faster)
|
// update points (without using prop, faster)
|
||||||
updatePoints(points: Vector3[]) {
|
updatePoints(points: Vector3[]) {
|
||||||
updateTubeGeometryPoints(this.geometry, points)
|
updateTubeGeometryPoints(this.geometry as TubeGeometry, points)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -64,8 +64,10 @@ export default defineComponent({
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
watch(() => this[p], (value) => {
|
watch(() => this[p], (value) => {
|
||||||
if (p === 'color') {
|
if (p === 'color') {
|
||||||
|
// @ts-ignore
|
||||||
this.material.color.set(value)
|
this.material.color.set(value)
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
this.material[p] = value
|
this.material[p] = value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -32,10 +32,12 @@ export default defineComponent({
|
|||||||
// TODO : use setProp, handle flatShading ?
|
// TODO : use setProp, handle flatShading ?
|
||||||
Object.keys(props).forEach(p => {
|
Object.keys(props).forEach(p => {
|
||||||
if (p === 'normalScale') return
|
if (p === 'normalScale') return
|
||||||
|
// @ts-ignore
|
||||||
watch(() => this[p], (value) => {
|
watch(() => this[p], (value) => {
|
||||||
if (p === 'emissive') {
|
if (p === 'emissive') {
|
||||||
material[p].set(value)
|
material[p].set(value)
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
material[p] = value
|
material[p] = value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { defineComponent } from 'vue'
|
import { meshComponent } from './Mesh'
|
||||||
import Mesh, { defaultSetup, meshComponent } from './Mesh'
|
|
||||||
import { props, createGeometry } from '../geometries/BoxGeometry'
|
import { props, createGeometry } from '../geometries/BoxGeometry'
|
||||||
|
|
||||||
export default meshComponent('Box', props, createGeometry)
|
export default meshComponent('Box', props, createGeometry)
|
||||||
|
|
||||||
|
// import { defineComponent } from 'vue'
|
||||||
|
// import Mesh, { meshComponent } from './Mesh'
|
||||||
|
//
|
||||||
// export default defineComponent({
|
// export default defineComponent({
|
||||||
// extends: Mesh,
|
// extends: Mesh,
|
||||||
// props,
|
// props,
|
||||||
|
@ -101,6 +101,7 @@ const Mesh = defineComponent({
|
|||||||
|
|
||||||
export default Mesh
|
export default Mesh
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export function meshComponent(name, props, createGeometry) {
|
export function meshComponent(name, props, createGeometry) {
|
||||||
return defineComponent({
|
return defineComponent({
|
||||||
name,
|
name,
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
import { defineComponent, watch } from 'vue';
|
|
||||||
import { FontLoader, TextGeometry } from 'three';
|
|
||||||
import Mesh from './Mesh.js';
|
|
||||||
|
|
||||||
const props = {
|
|
||||||
text: String,
|
|
||||||
fontSrc: String,
|
|
||||||
size: { type: Number, default: 80 },
|
|
||||||
height: { type: Number, default: 5 },
|
|
||||||
depth: { type: Number, default: 1 },
|
|
||||||
curveSegments: { type: Number, default: 12 },
|
|
||||||
bevelEnabled: { type: Boolean, default: false },
|
|
||||||
bevelThickness: { type: Number, default: 10 },
|
|
||||||
bevelSize: { type: Number, default: 8 },
|
|
||||||
bevelOffset: { type: Number, default: 0 },
|
|
||||||
bevelSegments: { type: Number, default: 5 },
|
|
||||||
align: { type: [Boolean, String], default: false },
|
|
||||||
};
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
extends: Mesh,
|
|
||||||
props,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: true,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
// add watchers
|
|
||||||
const watchProps = [
|
|
||||||
'text', 'size', 'height', 'curveSegments',
|
|
||||||
'bevelEnabled', 'bevelThickness', 'bevelSize', 'bevelOffset', 'bevelSegments',
|
|
||||||
'align',
|
|
||||||
];
|
|
||||||
watchProps.forEach(p => {
|
|
||||||
watch(() => this[p], () => {
|
|
||||||
if (this.font) this.refreshGeometry();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const loader = new FontLoader();
|
|
||||||
loader.load(this.fontSrc, (font) => {
|
|
||||||
this.loading = false;
|
|
||||||
this.font = font;
|
|
||||||
this.createGeometry();
|
|
||||||
this.initMesh();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
createGeometry() {
|
|
||||||
this.geometry = new TextGeometry(this.text, {
|
|
||||||
font: this.font,
|
|
||||||
size: this.size,
|
|
||||||
height: this.height,
|
|
||||||
depth: this.depth,
|
|
||||||
curveSegments: this.curveSegments,
|
|
||||||
bevelEnabled: this.bevelEnabled,
|
|
||||||
bevelThickness: this.bevelThickness,
|
|
||||||
bevelSize: this.bevelSize,
|
|
||||||
bevelOffset: this.bevelOffset,
|
|
||||||
bevelSegments: this.bevelSegments,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.align === 'center') {
|
|
||||||
this.geometry.center();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,7 +1,7 @@
|
|||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
import { TubeGeometry, Vector3 } from 'three'
|
||||||
import Mesh from './Mesh'
|
import Mesh from './Mesh'
|
||||||
import { props, createGeometry, updateTubeGeometryPoints } from '../geometries/TubeGeometry'
|
import { props, createGeometry, updateTubeGeometryPoints } from '../geometries/TubeGeometry'
|
||||||
import { Vector3 } from 'three'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
extends: Mesh,
|
extends: Mesh,
|
||||||
@ -16,7 +16,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
// update curve points (without using prop, faster)
|
// update curve points (without using prop, faster)
|
||||||
updatePoints(points: Vector3[]) {
|
updatePoints(points: Vector3[]) {
|
||||||
updateTubeGeometryPoints(this.geometry, points)
|
updateTubeGeometryPoints(this.geometry as TubeGeometry, points)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
__hmrId: 'Tube',
|
__hmrId: 'Tube',
|
||||||
|
@ -76,6 +76,7 @@ export const TroisJSVuePlugin = {
|
|||||||
]
|
]
|
||||||
|
|
||||||
comps.forEach(comp => {
|
comps.forEach(comp => {
|
||||||
|
// @ts-ignore
|
||||||
app.component(comp, TROIS[comp])
|
app.component(comp, TROIS[comp])
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user