-
-
Notifications
You must be signed in to change notification settings - Fork 309
/
Copy pathMaterial.ts
104 lines (95 loc) · 4.64 KB
/
Material.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { ComponentPropsOptions, ComponentPublicInstance, defineComponent, InjectionKey, PropType, watch } from 'vue'
import { Color, Material, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, PointsMaterial as TPointsMaterial, Texture, ShadowMaterial as TShadowMaterial } from 'three'
import { MeshInjectionKey, MeshInterface } from '../meshes/Mesh'
import { bindObjectProp, propsValues } from '../tools'
import { BasicMaterialPropsInterface, LambertMaterialPropsInterface, MaterialPropsInterface, PhongMaterialPropsInterface, PhysicalMaterialPropsInterface, PointsMaterialPropsInterface, StandardMaterialPropsInterface, ToonMaterialPropsInterface } from './types'
export interface MaterialSetupInterface {
mesh?: MeshInterface
material?: Material
createMaterial?(): Material
}
export interface MaterialInterface extends MaterialSetupInterface {
setTexture(texture: Texture | null, key: string): void
}
export interface MaterialPublicInterface extends ComponentPublicInstance, MaterialInterface {}
export const MaterialInjectionKey: InjectionKey<MaterialPublicInterface> = Symbol('Material')
const BaseMaterial = defineComponent({
emits: ['created'],
props: {
color: { type: String, default: '#ffffff' },
props: { type: Object as PropType<MaterialPropsInterface>, default: () => ({}) },
},
inject: {
mesh: MeshInjectionKey as symbol,
},
setup(): MaterialSetupInterface {
return {}
},
provide() {
return {
[MaterialInjectionKey as symbol]: this,
}
},
created() {
if (!this.mesh) {
console.error('Missing parent Mesh')
return
}
if (this.createMaterial) {
const material = this.material = this.createMaterial()
// @ts-ignore
watch(() => this.color, (value) => { material.color.set(value) })
bindObjectProp(this, 'props', material, false, this.setProp)
this.$emit('created', material)
this.mesh.setMaterial(material)
}
},
unmounted() {
this.material?.dispose()
},
methods: {
getMaterialParams() {
return { ...propsValues(this.$props, ['props']), ...this.props }
},
setProp(material: any, key: string, value: any, needsUpdate = false) {
const dstVal = material[key]
if (dstVal instanceof Color) dstVal.set(value)
else material[key] = value
material.needsUpdate = needsUpdate
},
setTexture(texture: Texture | null, key = 'map') {
this.setProp(this.material, key, texture, true)
},
},
render() {
return this.$slots.default ? this.$slots.default() : []
},
__hmrId: 'Material',
})
export default BaseMaterial
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function materialComponent<P extends Readonly<ComponentPropsOptions>>(
name: string,
props: P,
createMaterial: {(opts: any): Material}
) {
return defineComponent({
name,
extends: BaseMaterial,
props,
methods: {
createMaterial() {
return createMaterial(this.getMaterialParams())
},
},
})
}
// TODO : proper
export const BasicMaterial = materialComponent('BasicMaterial', { props: { type: Object as PropType<BasicMaterialPropsInterface>, default: () => ({}) } }, (opts) => new MeshBasicMaterial(opts))
export const LambertMaterial = materialComponent('LambertMaterial', { props: { type: Object as PropType<LambertMaterialPropsInterface>, default: () => ({}) } }, (opts) => new MeshLambertMaterial(opts))
export const PhongMaterial = materialComponent('PhongMaterial', { props: { type: Object as PropType<PhongMaterialPropsInterface>, default: () => ({}) } }, (opts) => new MeshPhongMaterial(opts))
export const PhysicalMaterial = materialComponent('PhysicalMaterial', { props: { type: Object as PropType<PhysicalMaterialPropsInterface>, default: () => ({}) } }, (opts) => new MeshPhysicalMaterial(opts))
export const PointsMaterial = materialComponent('PointsMaterial', { props: { type: Object as PropType<PointsMaterialPropsInterface>, default: () => ({}) } }, (opts) => new TPointsMaterial(opts))
export const ShadowMaterial = materialComponent('ShadowMaterial', { color: { type: String, default: '#000000' }, props: { type: Object as PropType<MaterialPropsInterface>, default: () => ({}) } }, (opts) => new TShadowMaterial(opts))
export const StandardMaterial = materialComponent('StandardMaterial', { props: { type: Object as PropType<StandardMaterialPropsInterface>, default: () => ({}) } }, (opts) => new MeshStandardMaterial(opts))
export const ToonMaterial = materialComponent('ToonMaterial', { props: { type: Object as PropType<ToonMaterialPropsInterface>, default: () => ({}) } }, (opts) => new MeshToonMaterial(opts))