mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
improve inject/provide types
This commit is contained in:
parent
9c41f1db6d
commit
cc87e699bd
@ -1,11 +1,12 @@
|
||||
import Stats from 'stats.js'
|
||||
import { RendererInjectionKey } from '../../core/Renderer'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
noSetup: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ['created'],
|
||||
inject: ['renderer'],
|
||||
inject: { renderer: RendererInjectionKey },
|
||||
setup({ noSetup }) {
|
||||
const stats = new Stats()
|
||||
if (!noSetup) {
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import useCannon from './useCannon.js'
|
||||
// import { bindProp } from '../../tools';
|
||||
import { RendererInjectionKey } from '../../core/Renderer'
|
||||
import { SceneInjectionKey } from '../../core/Scene'
|
||||
|
||||
export default defineComponent({
|
||||
inject: ['renderer', 'scene'],
|
||||
inject: {
|
||||
renderer: RendererInjectionKey,
|
||||
scene: SceneInjectionKey,
|
||||
},
|
||||
props: {
|
||||
gravity: { type: Object, default: () => ({ x: 0, y: 0, z: -9.82 }) },
|
||||
broadphase: { type: String },
|
||||
|
@ -1,21 +1,22 @@
|
||||
import { defineComponent, inject } from 'vue'
|
||||
import { RendererInterface } from './Renderer'
|
||||
import { defineComponent } from 'vue'
|
||||
// import { Camera } from 'three'
|
||||
// import { RendererInjectionKey, RendererInterface } from './Renderer'
|
||||
// import Object3D from './Object3D'
|
||||
|
||||
// export interface CameraSetupInterface {
|
||||
// renderer?: RendererInterface
|
||||
// camera: Camera
|
||||
// }
|
||||
|
||||
export default defineComponent({
|
||||
// TODO: eventually extend Object3D
|
||||
// extends: Object3D,
|
||||
|
||||
// don't work with typescript, bug ?
|
||||
// but works in sub components (injection, not typescript)
|
||||
inject: ['renderer'],
|
||||
// inject: { renderer: RendererInjectionKey as symbol },
|
||||
|
||||
setup() {
|
||||
// this works with typescript in sub component
|
||||
// but setup is not called
|
||||
const renderer = inject('renderer') as RendererInterface
|
||||
return { renderer }
|
||||
},
|
||||
// setup(): CameraSetupInterface {
|
||||
// return {}
|
||||
// },
|
||||
|
||||
render() {
|
||||
return this.$slots.default ? this.$slots.default() : []
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Object3D, Scene } from 'three'
|
||||
import { ComponentPublicInstance, defineComponent, inject, PropType, watch } from 'vue'
|
||||
import { ComponentPublicInstance, defineComponent, PropType, watch } from 'vue'
|
||||
import { bindProp } from '../tools'
|
||||
import { RendererInterface } from './Renderer'
|
||||
import { RendererInjectionKey, RendererInterface } from './Renderer'
|
||||
import { SceneInjectionKey } from './Scene'
|
||||
|
||||
export interface Object3DSetupInterface {
|
||||
renderer: RendererInterface
|
||||
scene: Scene
|
||||
renderer?: RendererInterface
|
||||
scene?: Scene
|
||||
o3d?: Object3D
|
||||
parent?: ComponentPublicInstance
|
||||
}
|
||||
@ -17,11 +18,11 @@ export interface Object3DInterface extends Object3DSetupInterface {
|
||||
remove(o: Object3D): void
|
||||
}
|
||||
|
||||
export function object3DSetup(): Object3DSetupInterface {
|
||||
const renderer = inject('renderer') as RendererInterface
|
||||
const scene = inject('scene') as Scene
|
||||
return { scene, renderer }
|
||||
}
|
||||
// export function object3DSetup(): Object3DSetupInterface {
|
||||
// const renderer = inject(RendererInjectionKey)
|
||||
// const scene = inject(SceneInjectionKey)
|
||||
// return { scene, renderer }
|
||||
// }
|
||||
|
||||
export interface Vector2PropInterface {
|
||||
x?: number
|
||||
@ -38,7 +39,11 @@ export interface EulerPropInterface extends Vector3PropInterface {
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Object3D',
|
||||
inject: ['renderer', 'scene'],
|
||||
// inject for sub components
|
||||
inject: {
|
||||
renderer: RendererInjectionKey as symbol,
|
||||
scene: SceneInjectionKey as symbol,
|
||||
},
|
||||
emits: ['created', 'ready'],
|
||||
props: {
|
||||
position: { type: Object as PropType<Vector3PropInterface>, default: () => ({ x: 0, y: 0, z: 0 }) },
|
||||
@ -48,10 +53,17 @@ export default defineComponent({
|
||||
autoRemove: { type: Boolean, default: true },
|
||||
userData: { type: Object, default: () => ({}) },
|
||||
},
|
||||
setup() {
|
||||
return object3DSetup()
|
||||
setup(): Object3DSetupInterface {
|
||||
// return object3DSetup()
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
created() {
|
||||
if (!this.renderer) {
|
||||
console.error('Missing parent Renderer')
|
||||
}
|
||||
if (!this.scene) {
|
||||
console.error('Missing parent Scene')
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
if (this.autoRemove) this.removeFromParent()
|
||||
@ -67,7 +79,6 @@ export default defineComponent({
|
||||
bindProp(this, 'scale', o3d)
|
||||
bindProp(this, 'userData', o3d.userData)
|
||||
|
||||
// TODO : fix lookat.x
|
||||
if (this.lookAt) o3d.lookAt(this.lookAt.x ?? 0, this.lookAt.y, this.lookAt.z)
|
||||
watch(() => this.lookAt, (v) => { o3d.lookAt(v.x ?? 0, v.y, v.z) }, { deep: true })
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { defineComponent, PropType, watch } from 'vue'
|
||||
import { defineComponent, inject, PropType, watch } from 'vue'
|
||||
import { OrthographicCamera } from 'three'
|
||||
import { bindProp } from '../tools'
|
||||
import Camera from './Camera'
|
||||
import { Vector3PropInterface } from './Object3D'
|
||||
import { RendererInjectionKey } from './Renderer'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Camera,
|
||||
@ -18,7 +19,14 @@ export default defineComponent({
|
||||
position: { type: Object as PropType<Vector3PropInterface>, default: () => ({ x: 0, y: 0, z: 0 }) },
|
||||
},
|
||||
setup(props) {
|
||||
const renderer = inject(RendererInjectionKey)
|
||||
if (!renderer) {
|
||||
console.error('Renderer not found')
|
||||
return
|
||||
}
|
||||
|
||||
const camera = new OrthographicCamera(props.left, props.right, props.top, props.bottom, props.near, props.far)
|
||||
renderer.camera = camera
|
||||
|
||||
bindProp(props, 'position', camera)
|
||||
|
||||
@ -32,10 +40,7 @@ export default defineComponent({
|
||||
})
|
||||
})
|
||||
|
||||
return { camera }
|
||||
},
|
||||
created() {
|
||||
this.renderer.camera = this.camera
|
||||
return { renderer, camera }
|
||||
},
|
||||
__hmrId: 'OrthographicCamera',
|
||||
})
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { defineComponent, PropType, watch } from 'vue'
|
||||
import { defineComponent, inject, PropType, watch } from 'vue'
|
||||
import { PerspectiveCamera } from 'three'
|
||||
import { bindProp } from '../tools'
|
||||
import Camera from './Camera'
|
||||
import { Vector3PropInterface } from './Object3D'
|
||||
import { RendererInjectionKey } from './Renderer'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Camera,
|
||||
@ -16,7 +17,14 @@ export default defineComponent({
|
||||
lookAt: { type: Object as PropType<Vector3PropInterface>, default: null },
|
||||
},
|
||||
setup(props) {
|
||||
const renderer = inject(RendererInjectionKey)
|
||||
if (!renderer) {
|
||||
console.error('Renderer not found')
|
||||
return
|
||||
}
|
||||
|
||||
const camera = new PerspectiveCamera(props.fov, props.aspect, props.near, props.far)
|
||||
renderer.camera = camera
|
||||
|
||||
bindProp(props, 'position', camera)
|
||||
|
||||
@ -33,10 +41,7 @@ export default defineComponent({
|
||||
})
|
||||
})
|
||||
|
||||
return { camera }
|
||||
},
|
||||
created() {
|
||||
this.renderer.camera = this.camera
|
||||
return { renderer, camera }
|
||||
},
|
||||
__hmrId: 'PerspectiveCamera',
|
||||
})
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Object3D } from 'three'
|
||||
import { defineComponent, inject, PropType } from 'vue'
|
||||
import usePointer, { IntersectObject, PointerInterface, PointerIntersectCallbackType } from './usePointer'
|
||||
import { RendererInterface } from './Renderer'
|
||||
import { RendererInjectionKey, RendererInterface } from './Renderer'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const emptyCallBack: PointerIntersectCallbackType = () => {}
|
||||
|
||||
interface RaycasterSetupInterface {
|
||||
renderer: RendererInterface
|
||||
renderer?: RendererInterface
|
||||
pointer?: PointerInterface
|
||||
}
|
||||
|
||||
@ -22,16 +22,22 @@ export default defineComponent({
|
||||
intersectMode: { type: String, default: 'move' },
|
||||
},
|
||||
setup(): RaycasterSetupInterface {
|
||||
const renderer = inject('renderer') as RendererInterface
|
||||
const renderer = inject(RendererInjectionKey)
|
||||
return { renderer }
|
||||
},
|
||||
mounted() {
|
||||
if (!this.renderer) {
|
||||
console.error('Renderer not found')
|
||||
return
|
||||
}
|
||||
const renderer = this.renderer
|
||||
|
||||
this.renderer.onMounted(() => {
|
||||
if (!this.renderer.camera) return
|
||||
if (!renderer.camera) return
|
||||
|
||||
this.pointer = usePointer({
|
||||
camera: this.renderer.camera,
|
||||
domElement: this.renderer.canvas,
|
||||
camera: renderer.camera,
|
||||
domElement: renderer.canvas,
|
||||
intersectObjects: this.getIntersectObjects(),
|
||||
onIntersectEnter: this.onPointerEnter,
|
||||
onIntersectOver: this.onPointerOver,
|
||||
@ -42,19 +48,19 @@ export default defineComponent({
|
||||
this.pointer.addListeners()
|
||||
|
||||
if (this.intersectMode === 'frame') {
|
||||
this.renderer.onBeforeRender(this.pointer.intersect)
|
||||
renderer.onBeforeRender(this.pointer.intersect)
|
||||
}
|
||||
})
|
||||
},
|
||||
unmounted() {
|
||||
if (this.pointer) {
|
||||
this.pointer.removeListeners()
|
||||
this.renderer.offBeforeRender(this.pointer.intersect)
|
||||
this.renderer?.offBeforeRender(this.pointer.intersect)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getIntersectObjects() {
|
||||
if (this.renderer.scene) {
|
||||
if (this.renderer && this.renderer.scene) {
|
||||
const children = this.renderer.scene.children.filter((c: Object3D) => ['Mesh', 'InstancedMesh'].includes(c.type))
|
||||
return children as IntersectObject[]
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { Camera, Scene, WebGLRenderer } from 'three'
|
||||
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import { defineComponent, InjectionKey, PropType } from 'vue'
|
||||
import useThree, { SizeInterface, ThreeConfigInterface, ThreeInterface } from './useThree'
|
||||
|
||||
type CallbackType<T> = (event: T) => void
|
||||
@ -86,6 +86,8 @@ export interface RendererInterface extends RendererSetupInterface {
|
||||
removeListener<T extends keyof EventCallbackMap>(t: T, cb: EventCallbackMap[T]): void
|
||||
}
|
||||
|
||||
export const RendererInjectionKey: InjectionKey<RendererInterface> = Symbol('Renderer')
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Renderer',
|
||||
props: {
|
||||
@ -162,7 +164,7 @@ export default defineComponent({
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
renderer: this,
|
||||
[RendererInjectionKey as symbol]: this,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -1,33 +1,43 @@
|
||||
import { defineComponent, inject, watch } from 'vue'
|
||||
import { Scene, Color, Object3D } from 'three'
|
||||
import { RendererInterface } from './Renderer'
|
||||
import { defineComponent, inject, InjectionKey, provide, watch } from 'vue'
|
||||
import { Scene, Color, Object3D, Texture } from 'three'
|
||||
import { RendererInjectionKey } from './Renderer'
|
||||
|
||||
export const SceneInjectionKey: InjectionKey<Scene> = Symbol('Scene')
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Scene',
|
||||
props: {
|
||||
// id: String,
|
||||
background: [String, Number],
|
||||
background: [String, Number, Object],
|
||||
},
|
||||
setup(props) {
|
||||
const renderer = inject('renderer') as RendererInterface
|
||||
const renderer = inject(RendererInjectionKey)
|
||||
const scene = new Scene()
|
||||
if (props.background) {
|
||||
scene.background = new Color(props.background)
|
||||
|
||||
if (!renderer) {
|
||||
console.error('Renderer not found')
|
||||
return
|
||||
}
|
||||
watch(() => props.background, (value) => { if (scene.background instanceof Color && value) scene.background.set(value) })
|
||||
return { renderer, scene }
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
scene: this.scene,
|
||||
|
||||
renderer.scene = scene
|
||||
provide(SceneInjectionKey, scene)
|
||||
|
||||
const setBackground = (value: any): void => {
|
||||
if (!value) return
|
||||
if (typeof value === 'string' || typeof value === 'number') {
|
||||
if (scene.background instanceof Color) scene.background.set(value)
|
||||
else scene.background = new Color(value)
|
||||
} else if (value instanceof Texture) {
|
||||
scene.background = value
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.renderer.scene = this.scene
|
||||
},
|
||||
methods: {
|
||||
add(o: Object3D) { this.scene.add(o) },
|
||||
remove(o: Object3D) { this.scene.remove(o) },
|
||||
|
||||
setBackground(props.background)
|
||||
watch(() => props.background, setBackground)
|
||||
|
||||
const add = (o: Object3D): void => { scene.add(o) }
|
||||
const remove = (o: Object3D): void => { scene.remove(o) }
|
||||
|
||||
return { add, remove }
|
||||
},
|
||||
render() {
|
||||
return this.$slots.default ? this.$slots.default() : []
|
||||
|
@ -12,6 +12,8 @@ export default defineComponent({
|
||||
extends: EffectPass,
|
||||
props,
|
||||
created() {
|
||||
if (!this.renderer) return
|
||||
|
||||
if (!this.renderer.scene) {
|
||||
console.error('Missing Scene')
|
||||
return
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { defineComponent, inject } from 'vue'
|
||||
import { defineComponent, inject, InjectionKey } from 'vue'
|
||||
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'
|
||||
import { Pass } from 'three/examples/jsm/postprocessing/Pass'
|
||||
import { RendererInterface } from '../core/Renderer'
|
||||
import { RendererInjectionKey, RendererInterface } from '../core/Renderer'
|
||||
|
||||
interface EffectComposerSetupInterface {
|
||||
renderer: RendererInterface
|
||||
renderer?: RendererInterface
|
||||
composer?: EffectComposer
|
||||
}
|
||||
|
||||
@ -13,34 +13,38 @@ export interface EffectComposerInterface extends EffectComposerSetupInterface {
|
||||
removePass(pass: Pass): void
|
||||
}
|
||||
|
||||
export const ComposerInjectionKey: InjectionKey<EffectComposerInterface> = Symbol('Composer')
|
||||
|
||||
export default defineComponent({
|
||||
setup(): EffectComposerSetupInterface {
|
||||
const renderer = inject('renderer') as RendererInterface
|
||||
return {
|
||||
renderer,
|
||||
}
|
||||
const renderer = inject(RendererInjectionKey)
|
||||
return { renderer }
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
composer: this,
|
||||
[ComposerInjectionKey as symbol]: this,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (!this.renderer) {
|
||||
console.error('Renderer not found')
|
||||
return
|
||||
}
|
||||
const renderer = this.renderer
|
||||
|
||||
const composer = new EffectComposer(this.renderer.renderer)
|
||||
this.composer = composer
|
||||
this.renderer.composer = composer
|
||||
|
||||
// this.renderer.onInit(() => {
|
||||
this.renderer.addListener('init', () => {
|
||||
this.renderer.renderer.autoClear = false
|
||||
renderer.addListener('init', () => {
|
||||
renderer.renderer.autoClear = false
|
||||
this.resize()
|
||||
// this.renderer.onResize(this.resize)
|
||||
this.renderer.addListener('resize', this.resize)
|
||||
renderer.addListener('resize', this.resize)
|
||||
})
|
||||
},
|
||||
unmounted() {
|
||||
// this.renderer.offResize(this.resize)
|
||||
this.renderer.removeListener('resize', this.resize)
|
||||
this.renderer?.removeListener('resize', this.resize)
|
||||
},
|
||||
methods: {
|
||||
addPass(pass: Pass) {
|
||||
@ -50,7 +54,9 @@ export default defineComponent({
|
||||
this.composer?.removePass(pass)
|
||||
},
|
||||
resize() {
|
||||
this.composer?.setSize(this.renderer.size.width, this.renderer.size.height)
|
||||
if (this.composer && this.renderer) {
|
||||
this.composer.setSize(this.renderer.size.width, this.renderer.size.height)
|
||||
}
|
||||
},
|
||||
},
|
||||
render() {
|
||||
|
@ -1,37 +1,42 @@
|
||||
import { Pass } from 'three/examples/jsm/postprocessing/Pass'
|
||||
import { defineComponent, inject } from 'vue'
|
||||
import { RendererInterface } from '../core/Renderer'
|
||||
import { EffectComposerInterface } from './EffectComposer'
|
||||
import { defineComponent } from 'vue'
|
||||
import { RendererInjectionKey, RendererInterface } from '../core/Renderer'
|
||||
import { ComposerInjectionKey, EffectComposerInterface } from './EffectComposer'
|
||||
|
||||
export interface EffectSetupInterface {
|
||||
renderer: RendererInterface
|
||||
composer: EffectComposerInterface
|
||||
renderer?: RendererInterface
|
||||
composer?: EffectComposerInterface
|
||||
pass?: Pass
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
inject: ['renderer', 'composer'],
|
||||
// inject for sub components
|
||||
inject: {
|
||||
renderer: RendererInjectionKey as symbol,
|
||||
composer: ComposerInjectionKey as symbol,
|
||||
},
|
||||
emits: ['ready'],
|
||||
setup(): EffectSetupInterface {
|
||||
const renderer = inject('renderer') as RendererInterface
|
||||
const composer = inject('composer') as EffectComposerInterface
|
||||
return { renderer, composer }
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
if (!this.composer) {
|
||||
console.error('Missing parent EffectComposer')
|
||||
}
|
||||
if (!this.renderer) {
|
||||
console.error('Missing parent Renderer')
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
if (this.pass) {
|
||||
this.composer.removePass(this.pass);
|
||||
this.composer?.removePass(this.pass);
|
||||
(this.pass as any).dispose?.()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initEffectPass(pass: Pass) {
|
||||
this.pass = pass
|
||||
this.composer.addPass(pass)
|
||||
this.composer?.addPass(pass)
|
||||
this.$emit('ready', pass)
|
||||
},
|
||||
},
|
||||
|
@ -10,12 +10,12 @@ export default defineComponent({
|
||||
const pass = new ShaderPass(FXAAShader)
|
||||
|
||||
// resize will be first called in renderer init
|
||||
this.renderer.addListener('resize', this.resize)
|
||||
this.renderer?.addListener('resize', this.resize)
|
||||
|
||||
this.initEffectPass(pass)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.removeListener('resize', this.resize)
|
||||
this.renderer?.removeListener('resize', this.resize)
|
||||
},
|
||||
methods: {
|
||||
resize({ size }: { size: SizeInterface }) {
|
||||
|
@ -15,6 +15,8 @@ export default defineComponent({
|
||||
extends: EffectPass,
|
||||
props,
|
||||
created() {
|
||||
if (!this.renderer) return
|
||||
|
||||
const pass = new HalftonePass(this.renderer.size.width, this.renderer.size.height, {})
|
||||
|
||||
Object.keys(props).forEach(p => {
|
||||
|
@ -5,6 +5,8 @@ import EffectPass from './EffectPass'
|
||||
export default defineComponent({
|
||||
extends: EffectPass,
|
||||
created() {
|
||||
if (!this.renderer) return
|
||||
|
||||
if (!this.renderer.scene) {
|
||||
console.error('Missing Scene')
|
||||
return
|
||||
|
@ -5,6 +5,8 @@ import EffectPass from './EffectPass'
|
||||
export default defineComponent({
|
||||
extends: EffectPass,
|
||||
created() {
|
||||
if (!this.renderer) return
|
||||
|
||||
const pass = new SMAAPass(this.renderer.size.width, this.renderer.size.height)
|
||||
this.initEffectPass(pass)
|
||||
},
|
||||
|
@ -11,6 +11,8 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (!this.renderer) return
|
||||
|
||||
if (!this.renderer.scene) {
|
||||
console.error('Missing Scene')
|
||||
return
|
||||
|
@ -26,6 +26,8 @@ export default defineComponent({
|
||||
return { uniforms1: {}, uniforms2: {} }
|
||||
},
|
||||
created() {
|
||||
if (!this.composer) return
|
||||
|
||||
this.pass1 = new ShaderPass(TiltShift)
|
||||
this.pass2 = new ShaderPass(TiltShift)
|
||||
|
||||
@ -57,7 +59,7 @@ export default defineComponent({
|
||||
this.composer.addPass(this.pass2)
|
||||
},
|
||||
unmounted() {
|
||||
if (this.pass2) this.composer.removePass(this.pass2)
|
||||
if (this.composer && this.pass2) this.composer.removePass(this.pass2)
|
||||
},
|
||||
methods: {
|
||||
updateFocusLine() {
|
||||
|
@ -13,6 +13,8 @@ export default defineComponent({
|
||||
extends: EffectPass,
|
||||
props,
|
||||
created() {
|
||||
if (!this.renderer) return
|
||||
|
||||
const size = new Vector2(this.renderer.size.width, this.renderer.size.height)
|
||||
const pass = new UnrealBloomPass(size, this.strength, this.radius, this.threshold)
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { BufferGeometry } from 'three'
|
||||
import { defineComponent, inject, watch } from 'vue'
|
||||
import { MeshInterface } from '../meshes/Mesh'
|
||||
import { MeshInjectionKey, MeshInterface } from '../meshes/Mesh'
|
||||
|
||||
export interface GeometryInterface {
|
||||
geometry?: BufferGeometry
|
||||
export interface GeometrySetupInterface {
|
||||
mesh?: MeshInterface
|
||||
watchProps: string[]
|
||||
geometry?: BufferGeometry
|
||||
watchProps?: string[]
|
||||
}
|
||||
|
||||
function defaultSetup(): GeometryInterface {
|
||||
const mesh = inject('mesh') as MeshInterface
|
||||
const watchProps: string[] = []
|
||||
return { mesh, watchProps }
|
||||
}
|
||||
// function defaultSetup(): GeometryInterface {
|
||||
// const mesh = inject('mesh') as MeshInterface
|
||||
// const watchProps: string[] = []
|
||||
// return { mesh, watchProps }
|
||||
// }
|
||||
|
||||
const Geometry = defineComponent({
|
||||
props: {
|
||||
@ -20,8 +20,12 @@ const Geometry = defineComponent({
|
||||
rotateY: Number,
|
||||
rotateZ: Number,
|
||||
},
|
||||
setup() {
|
||||
return defaultSetup()
|
||||
// inject for sub components
|
||||
inject: {
|
||||
mesh: MeshInjectionKey as symbol,
|
||||
},
|
||||
setup(): GeometrySetupInterface {
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
if (!this.mesh) {
|
||||
@ -29,37 +33,31 @@ const Geometry = defineComponent({
|
||||
return
|
||||
}
|
||||
|
||||
Object.entries(this.$props).forEach(e => this.watchProps.push(e[0]))
|
||||
|
||||
this.createGeometry()
|
||||
this.rotateGeometry()
|
||||
if (this.geometry) this.mesh.setGeometry(this.geometry)
|
||||
|
||||
this.addWatchers()
|
||||
Object.keys(this.$props).forEach(prop => {
|
||||
// @ts-ignore
|
||||
watch(() => this[prop], this.refreshGeometry)
|
||||
})
|
||||
},
|
||||
unmounted() {
|
||||
this.geometry?.dispose()
|
||||
},
|
||||
methods: {
|
||||
createGeometry() {},
|
||||
addWatchers() {
|
||||
this.watchProps.forEach(prop => {
|
||||
// @ts-ignore
|
||||
watch(() => this[prop], () => {
|
||||
this.refreshGeometry()
|
||||
})
|
||||
})
|
||||
},
|
||||
rotateGeometry() {
|
||||
if (this.rotateX) this.geometry?.rotateX(this.rotateX)
|
||||
if (this.rotateY) this.geometry?.rotateY(this.rotateY)
|
||||
if (this.rotateZ) this.geometry?.rotateZ(this.rotateZ)
|
||||
if (!this.geometry) return
|
||||
if (this.rotateX) this.geometry.rotateX(this.rotateX)
|
||||
if (this.rotateY) this.geometry.rotateY(this.rotateY)
|
||||
if (this.rotateZ) this.geometry.rotateZ(this.rotateZ)
|
||||
},
|
||||
refreshGeometry() {
|
||||
const oldGeo = this.geometry
|
||||
this.createGeometry()
|
||||
this.rotateGeometry()
|
||||
if (this.geometry) this.mesh?.setGeometry(this.geometry)
|
||||
if (this.geometry && this.mesh) this.mesh.setGeometry(this.geometry)
|
||||
oldGeo?.dispose()
|
||||
},
|
||||
},
|
||||
@ -74,8 +72,8 @@ export function geometryComponent(name, props, createGeometry) {
|
||||
name,
|
||||
extends: Geometry,
|
||||
props,
|
||||
setup() {
|
||||
return defaultSetup()
|
||||
setup(): GeometrySetupInterface {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
createGeometry() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { defineComponent, InjectionKey, watch } from 'vue'
|
||||
import { FrontSide, Material, Texture } from 'three'
|
||||
import { MeshInterface } from '../meshes/Mesh'
|
||||
import { MeshInjectionKey, MeshInterface } from '../meshes/Mesh'
|
||||
|
||||
export interface MaterialSetupInterface {
|
||||
mesh?: MeshInterface
|
||||
@ -13,8 +13,13 @@ export interface MaterialInterface extends MaterialSetupInterface {
|
||||
setTexture(texture: Texture | null, key: string): void
|
||||
}
|
||||
|
||||
export const MaterialInjectionKey: InjectionKey<MaterialInterface> = Symbol('Material')
|
||||
|
||||
export default defineComponent({
|
||||
inject: ['mesh'],
|
||||
// inject for sub components
|
||||
inject: {
|
||||
mesh: MeshInjectionKey as symbol,
|
||||
},
|
||||
props: {
|
||||
color: { type: [String, Number], default: '#ffffff' },
|
||||
depthTest: { type: Boolean, default: true },
|
||||
@ -30,7 +35,7 @@ export default defineComponent({
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
material: this,
|
||||
[MaterialInjectionKey as symbol]: this,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { defineComponent, PropType, watch } from 'vue'
|
||||
import { ClampToEdgeWrapping, LinearFilter, LinearMipmapLinearFilter, RGBAFormat, ShaderMaterial, Texture, TextureLoader, UVMapping } from 'three'
|
||||
import { ClampToEdgeWrapping, LinearFilter, LinearMipmapLinearFilter, ShaderMaterial, Texture, TextureLoader, UVMapping } from 'three'
|
||||
import { bindProp } from '../tools'
|
||||
import { MaterialInterface } from './Material'
|
||||
import { MaterialInjectionKey, MaterialInterface } from './Material'
|
||||
|
||||
export interface TexureInterface {
|
||||
material?: MaterialInterface
|
||||
@ -9,7 +9,9 @@ export interface TexureInterface {
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
inject: ['material'],
|
||||
inject: {
|
||||
material: MaterialInjectionKey as symbol,
|
||||
},
|
||||
props: {
|
||||
name: { type: String, default: 'map' },
|
||||
uniform: String,
|
||||
@ -53,7 +55,7 @@ export default defineComponent({
|
||||
if (this.texture && this.material) {
|
||||
this.material.setTexture(this.texture, this.name)
|
||||
if (this.material.material instanceof ShaderMaterial && this.uniform) {
|
||||
// this.material.uniforms[this.uniform] = { value: this.texture }
|
||||
(this.material as any).uniforms[this.uniform] = { value: this.texture }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { DoubleSide, MeshBasicMaterial, PlaneGeometry, Texture, TextureLoader } from 'three'
|
||||
import Mesh, { MeshSetupInterface } from './Mesh'
|
||||
import { object3DSetup } from '../core/Object3D'
|
||||
|
||||
interface ImageSetupInterface extends MeshSetupInterface {
|
||||
material?: MeshBasicMaterial
|
||||
@ -20,9 +19,11 @@ export default defineComponent({
|
||||
keepSize: Boolean,
|
||||
},
|
||||
setup(): ImageSetupInterface {
|
||||
return object3DSetup()
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
if (!this.renderer) return
|
||||
|
||||
this.geometry = new PlaneGeometry(1, 1, this.widthSegments, this.heightSegments)
|
||||
this.material = new MeshBasicMaterial({ side: DoubleSide, map: this.loadTexture() })
|
||||
|
||||
@ -37,7 +38,7 @@ export default defineComponent({
|
||||
if (this.keepSize) this.renderer.onResize(this.resize)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offResize(this.resize)
|
||||
this.renderer?.offResize(this.resize)
|
||||
},
|
||||
methods: {
|
||||
loadTexture() {
|
||||
@ -56,7 +57,7 @@ export default defineComponent({
|
||||
this.$emit('loaded', texture)
|
||||
},
|
||||
resize() {
|
||||
if (!this.texture) return
|
||||
if (!this.renderer || !this.texture) return
|
||||
const screen = this.renderer.size
|
||||
const iW = this.texture.image.width
|
||||
const iH = this.texture.image.height
|
||||
|
@ -10,6 +10,8 @@ export default defineComponent({
|
||||
},
|
||||
methods: {
|
||||
initMesh() {
|
||||
if (!this.renderer) return
|
||||
|
||||
if (!this.geometry || !this.material) {
|
||||
console.error('Missing geometry and/or material')
|
||||
return false
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ComponentPropsOptions, defineComponent, watch } from 'vue'
|
||||
import { ComponentPropsOptions, defineComponent, InjectionKey, watch } from 'vue'
|
||||
import { BufferGeometry, Material, Mesh as TMesh } from 'three'
|
||||
import Object3D, { object3DSetup, Object3DSetupInterface } from '../core/Object3D'
|
||||
import Object3D, { Object3DSetupInterface } from '../core/Object3D'
|
||||
import { bindProp } from '../tools'
|
||||
|
||||
export const pointerProps = {
|
||||
@ -25,6 +25,8 @@ export interface MeshInterface extends MeshSetupInterface {
|
||||
setMaterial(m: Material): void
|
||||
}
|
||||
|
||||
export const MeshInjectionKey: InjectionKey<MeshInterface> = Symbol('Mesh')
|
||||
|
||||
const Mesh = defineComponent({
|
||||
name: 'Mesh',
|
||||
extends: Object3D,
|
||||
@ -34,11 +36,11 @@ const Mesh = defineComponent({
|
||||
...pointerProps,
|
||||
},
|
||||
setup(): MeshSetupInterface {
|
||||
return object3DSetup()
|
||||
return {}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
mesh: this,
|
||||
[MeshInjectionKey as symbol]: this,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -60,7 +62,7 @@ const Mesh = defineComponent({
|
||||
this.onPointerDown ||
|
||||
this.onPointerUp ||
|
||||
this.onClick) {
|
||||
this.renderer.three.addIntersectObject(mesh)
|
||||
if (this.renderer) this.renderer.three.addIntersectObject(mesh)
|
||||
}
|
||||
|
||||
this.mesh = mesh
|
||||
@ -92,7 +94,7 @@ const Mesh = defineComponent({
|
||||
},
|
||||
unmounted() {
|
||||
if (this.mesh) {
|
||||
this.renderer.three?.removeIntersectObject(this.mesh)
|
||||
if (this.renderer) this.renderer.three.removeIntersectObject(this.mesh)
|
||||
}
|
||||
// for predefined mesh (geometry/material are not unmounted)
|
||||
if (this.geometry) this.geometry.dispose()
|
||||
@ -110,7 +112,7 @@ export function meshComponent(name, props, createGeometry) {
|
||||
extends: Mesh,
|
||||
props,
|
||||
setup(): MeshSetupInterface {
|
||||
return object3DSetup()
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
this.createGeometry()
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { Sprite, SpriteMaterial, Texture, TextureLoader } from 'three'
|
||||
import Object3D, { object3DSetup, Object3DSetupInterface } from '../core/Object3D'
|
||||
import Object3D, { Object3DSetupInterface } from '../core/Object3D'
|
||||
|
||||
interface SpriteSetupInterface extends Object3DSetupInterface {
|
||||
texture?: Texture
|
||||
@ -15,7 +15,7 @@ export default defineComponent({
|
||||
src: { type: String, required: true },
|
||||
},
|
||||
setup(): SpriteSetupInterface {
|
||||
return object3DSetup()
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
this.texture = new TextureLoader().load(this.src, this.onLoaded)
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { Font, FontLoader, TextGeometry } from 'three'
|
||||
import Mesh, { MeshSetupInterface } from './Mesh'
|
||||
import { object3DSetup } from '../core/Object3D'
|
||||
|
||||
interface TextSetupInterface extends MeshSetupInterface {
|
||||
geometry?: TextGeometry
|
||||
@ -27,7 +26,7 @@ export default defineComponent({
|
||||
extends: Mesh,
|
||||
props,
|
||||
setup(): TextSetupInterface {
|
||||
return object3DSetup()
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
if (!this.fontSrc) {
|
||||
|
Loading…
Reference in New Issue
Block a user