mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
refactor materials #54
This commit is contained in:
parent
cee01894b9
commit
1735a2150c
@ -1,19 +0,0 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { MeshBasicMaterial } from 'three'
|
||||
import { bindProps, propsValues } from '../tools'
|
||||
import Material, { wireframeProps } from './Material'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props: {
|
||||
...wireframeProps,
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const material = new MeshBasicMaterial(propsValues(this.$props))
|
||||
bindProps(this, Object.keys(wireframeProps), material)
|
||||
return material
|
||||
},
|
||||
},
|
||||
__hmrId: 'BasicMaterial',
|
||||
})
|
@ -1,19 +0,0 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { MeshLambertMaterial } from 'three'
|
||||
import { bindProps, propsValues } from '../tools'
|
||||
import Material, { wireframeProps } from './Material'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props: {
|
||||
...wireframeProps,
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const material = new MeshLambertMaterial(propsValues(this.$props))
|
||||
bindProps(this, Object.keys(wireframeProps), material)
|
||||
return material
|
||||
},
|
||||
},
|
||||
__hmrId: 'LambertMaterial',
|
||||
})
|
@ -1,22 +1,17 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { MeshMatcapMaterial, TextureLoader } from 'three'
|
||||
import { propsValues, getMatcapUrl } from '../tools'
|
||||
import Material from './Material'
|
||||
import { materialComponent } from './Material'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props: {
|
||||
export default materialComponent(
|
||||
'MatcapMaterial',
|
||||
{
|
||||
src: String,
|
||||
name: { type: String, default: '0404E8_0404B5_0404CB_3333FC' },
|
||||
flatShading: Boolean,
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const src = this.src ? this.src : getMatcapUrl(this.name)
|
||||
const opts = propsValues(this.$props, ['src', 'name'])
|
||||
opts.matcap = new TextureLoader().load(src)
|
||||
return new MeshMatcapMaterial(opts)
|
||||
},
|
||||
},
|
||||
__hmrId: 'MatcapMaterial',
|
||||
})
|
||||
(opts) => {
|
||||
const src = opts.src ? opts.src : getMatcapUrl(opts.name)
|
||||
const props = propsValues(opts, ['src', 'name'])
|
||||
props.matcap = new TextureLoader().load(src)
|
||||
return new MeshMatcapMaterial(props)
|
||||
}
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ComponentPublicInstance, defineComponent, InjectionKey } from 'vue'
|
||||
import { Material, Texture } from 'three'
|
||||
import { ComponentPropsOptions, ComponentPublicInstance, defineComponent, InjectionKey, watch } from 'vue'
|
||||
import { Color, Material, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, PointsMaterial as TPointsMaterial, Texture } from 'three'
|
||||
import { MeshInjectionKey, MeshInterface } from '../meshes/Mesh'
|
||||
import { bindObjectProp } from '../tools'
|
||||
|
||||
@ -17,15 +17,14 @@ export interface MaterialPublicInterface extends ComponentPublicInstance, Materi
|
||||
|
||||
export const MaterialInjectionKey: InjectionKey<MaterialPublicInterface> = Symbol('Material')
|
||||
|
||||
export default defineComponent({
|
||||
// inject for sub components
|
||||
inject: {
|
||||
mesh: MeshInjectionKey as symbol,
|
||||
},
|
||||
const BaseMaterial = defineComponent({
|
||||
props: {
|
||||
color: { type: String, default: '#ffffff' },
|
||||
props: { type: Object, default: () => ({}) },
|
||||
},
|
||||
inject: {
|
||||
mesh: MeshInjectionKey as symbol,
|
||||
},
|
||||
setup(): MaterialSetupInterface {
|
||||
return {}
|
||||
},
|
||||
@ -41,22 +40,25 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
if (this.createMaterial) {
|
||||
this.material = this.createMaterial()
|
||||
bindObjectProp(this, 'props', this.material, this.setProp)
|
||||
this.mesh.setMaterial(this.material)
|
||||
const material = this.material = this.createMaterial()
|
||||
// @ts-ignore
|
||||
watch(() => this.color, (value) => { material.color.set(value) })
|
||||
bindObjectProp(this, 'props', material, false, this.setProp)
|
||||
this.mesh.setMaterial(material)
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
this.material?.dispose()
|
||||
},
|
||||
methods: {
|
||||
getProps() {
|
||||
getMaterialParams() {
|
||||
return { color: this.color, ...this.props }
|
||||
},
|
||||
setProp(dst: any, key: string, value: any, needsUpdate = false) {
|
||||
if (key === 'color') dst[key].set(value)
|
||||
else dst[key] = value
|
||||
dst.needsUpdate = needsUpdate
|
||||
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, key, texture, true)
|
||||
@ -68,10 +70,30 @@ export default defineComponent({
|
||||
__hmrId: 'Material',
|
||||
})
|
||||
|
||||
export const wireframeProps = {
|
||||
wireframe: { type: Boolean, default: false },
|
||||
// not needed for WebGL
|
||||
// wireframeLinecap: { type: String, default: 'round' },
|
||||
// wireframeLinejoin: { type: String, default: 'round' },
|
||||
wireframeLinewidth: { type: Number, default: 1 }, // not really useful
|
||||
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())
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const BasicMaterial = materialComponent('BasicMaterial', {}, (opts) => new MeshBasicMaterial(opts))
|
||||
export const LambertMaterial = materialComponent('LambertMaterial', {}, (opts) => new MeshLambertMaterial(opts))
|
||||
export const PhongMaterial = materialComponent('PhongMaterial', {}, (opts) => new MeshPhongMaterial(opts))
|
||||
export const PhysicalMaterial = materialComponent('PhysicalMaterial', {}, (opts) => new MeshPhysicalMaterial(opts))
|
||||
export const PointsMaterial = materialComponent('PointsMaterial', {}, (opts) => new TPointsMaterial(opts))
|
||||
export const StandardMaterial = materialComponent('StandardMaterial', {}, (opts) => new MeshStandardMaterial(opts))
|
||||
export const ToonMaterial = materialComponent('ToonMaterial', {}, (opts) => new MeshToonMaterial(opts))
|
||||
|
@ -1,40 +0,0 @@
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { MeshPhongMaterial } from 'three'
|
||||
import { bindProps, propsValues } from '../tools'
|
||||
import Material, { wireframeProps } from './Material'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props: {
|
||||
emissive: { type: [Number, String], default: 0 },
|
||||
emissiveIntensity: { type: Number, default: 1 },
|
||||
reflectivity: { type: Number, default: 1 },
|
||||
shininess: { type: Number, default: 30 },
|
||||
specular: { type: [String, Number], default: 0x111111 },
|
||||
flatShading: Boolean,
|
||||
...wireframeProps,
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const material = new MeshPhongMaterial(propsValues(this.$props))
|
||||
|
||||
// TODO : handle flatShading ?
|
||||
const watchProps = ['emissive', 'emissiveIntensity', 'reflectivity', 'shininess', 'specular']
|
||||
watchProps.forEach(p => {
|
||||
// @ts-ignore
|
||||
watch(() => this[p], (value) => {
|
||||
if (p === 'emissive' || p === 'specular') {
|
||||
material[p].set(value)
|
||||
} else {
|
||||
// @ts-ignore
|
||||
material[p] = value
|
||||
}
|
||||
})
|
||||
})
|
||||
bindProps(this, Object.keys(wireframeProps), material)
|
||||
|
||||
return material
|
||||
},
|
||||
},
|
||||
__hmrId: 'PhongMaterial',
|
||||
})
|
@ -1,17 +0,0 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { MeshPhysicalMaterial } from 'three'
|
||||
import { propsValues } from '../tools'
|
||||
import StandardMaterial from './StandardMaterial'
|
||||
|
||||
export default defineComponent({
|
||||
extends: StandardMaterial,
|
||||
props: {
|
||||
flatShading: Boolean,
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
return new MeshPhysicalMaterial(propsValues(this.$props))
|
||||
},
|
||||
},
|
||||
__hmrId: 'PhysicalMaterial',
|
||||
})
|
@ -1,19 +0,0 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { PointsMaterial } from 'three'
|
||||
import { propsValues } from '../tools'
|
||||
import Material from './Material'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props: {
|
||||
size: { type: Number, default: 10 },
|
||||
sizeAttenuation: { type: Boolean, default: true },
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const material = new PointsMaterial(propsValues(this.$props))
|
||||
return material
|
||||
},
|
||||
},
|
||||
__hmrId: 'PointsMaterial',
|
||||
})
|
@ -1,6 +1,5 @@
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { ShaderMaterial } from 'three'
|
||||
import Material from './Material'
|
||||
import { materialComponent } from './Material'
|
||||
import { propsValues } from '../tools'
|
||||
|
||||
const defaultVertexShader = `
|
||||
@ -18,24 +17,39 @@ const defaultFragmentShader = `
|
||||
}
|
||||
`
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props: {
|
||||
uniforms: { type: Object, default: () => ({}) },
|
||||
vertexShader: { type: String, default: defaultVertexShader },
|
||||
fragmentShader: { type: String, default: defaultFragmentShader },
|
||||
export default materialComponent(
|
||||
'ShaderMaterial',
|
||||
{
|
||||
props: { type: Object, default: () => ({
|
||||
uniforms: {},
|
||||
vertexShader: defaultVertexShader,
|
||||
fragmentShader: defaultFragmentShader,
|
||||
}) },
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const material = new ShaderMaterial(propsValues(this.$props, ['color']));
|
||||
(opts) => {
|
||||
const material = new ShaderMaterial(propsValues(opts, ['color']));
|
||||
return material
|
||||
}
|
||||
)
|
||||
|
||||
['vertexShader', 'fragmentShader'].forEach(p => {
|
||||
// @ts-ignore
|
||||
watch(() => this[p], (value) => { material[p] = value; material.needsUpdate = true })
|
||||
})
|
||||
// export default defineComponent({
|
||||
// extends: Material,
|
||||
// props: {
|
||||
// uniforms: { type: Object, default: () => ({}) },
|
||||
// vertexShader: { type: String, default: defaultVertexShader },
|
||||
// fragmentShader: { type: String, default: defaultFragmentShader },
|
||||
// },
|
||||
// methods: {
|
||||
// createMaterial() {
|
||||
// const material = new ShaderMaterial(propsValues(this.$props, ['color']));
|
||||
|
||||
return material
|
||||
},
|
||||
},
|
||||
__hmrId: 'ShaderMaterial',
|
||||
})
|
||||
// ['vertexShader', 'fragmentShader'].forEach(p => {
|
||||
// // @ts-ignore
|
||||
// watch(() => this[p], (value) => { material[p] = value; material.needsUpdate = true })
|
||||
// })
|
||||
|
||||
// return material
|
||||
// },
|
||||
// },
|
||||
// __hmrId: 'ShaderMaterial',
|
||||
// })
|
||||
|
@ -1,54 +0,0 @@
|
||||
import { defineComponent, PropType, watch } from 'vue'
|
||||
import { MeshStandardMaterial } from 'three'
|
||||
import { bindProp, bindProps, propsValues } from '../tools'
|
||||
import Material, { wireframeProps } from './Material'
|
||||
import { Vector2PropInterface } from '../core/Object3D'
|
||||
|
||||
const props = {
|
||||
aoMapIntensity: { type: Number, default: 1 },
|
||||
bumpScale: { type: Number, default: 1 },
|
||||
displacementBias: { type: Number, default: 0 },
|
||||
displacementScale: { type: Number, default: 1 },
|
||||
emissive: { type: [String, Number] as PropType<string | number>, default: 0 },
|
||||
emissiveIntensity: { type: Number, default: 1 },
|
||||
envMapIntensity: { type: Number, default: 1 },
|
||||
lightMapIntensity: { type: Number, default: 1 },
|
||||
metalness: { type: Number, default: 0 },
|
||||
normalScale: { type: Object as PropType<Vector2PropInterface>, default: () => ({ x: 1, y: 1 }) },
|
||||
roughness: { type: Number, default: 1 },
|
||||
refractionRatio: { type: Number, default: 0.98 },
|
||||
flatShading: Boolean,
|
||||
} as const
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props: {
|
||||
...props,
|
||||
...wireframeProps,
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const material = new MeshStandardMaterial(propsValues(this.$props, ['normalScale']))
|
||||
|
||||
// TODO : use setProp, handle flatShading ?
|
||||
Object.keys(props).forEach(p => {
|
||||
if (p === 'normalScale') return
|
||||
// @ts-ignore
|
||||
watch(() => this[p], (value) => {
|
||||
if (p === 'emissive') {
|
||||
material[p].set(value)
|
||||
} else {
|
||||
// @ts-ignore
|
||||
material[p] = value
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
bindProp(this, 'normalScale', material)
|
||||
bindProps(this, Object.keys(wireframeProps), material)
|
||||
|
||||
return material
|
||||
},
|
||||
},
|
||||
__hmrId: 'StandardMaterial',
|
||||
})
|
@ -2,47 +2,50 @@ import { defineComponent, PropType } from 'vue'
|
||||
import { Color, ShaderMaterial, UniformsUtils } from 'three'
|
||||
import SubsurfaceScatteringShader from './SubsurfaceScatteringShader'
|
||||
import Material from './Material'
|
||||
// import { bindProps, propsValues } from '../tools'
|
||||
import { bindObjectProp } from '../tools'
|
||||
|
||||
const props = {
|
||||
color: { type: [String, Number] as PropType<string | number>, default: '#ffffff' },
|
||||
thicknessColor: { type: [String, Number] as PropType<string | number>, default: '#ffffff' },
|
||||
thicknessDistortion: { type: Number, default: 0.4 },
|
||||
thicknessAmbient: { type: Number, default: 0.01 },
|
||||
thicknessAttenuation: { type: Number, default: 0.7 },
|
||||
thicknessPower: { type: Number, default: 2 },
|
||||
thicknessScale: { type: Number, default: 4 },
|
||||
} as const
|
||||
export interface SubSurfaceMaterialUniformsInterface {
|
||||
diffuse?: string | number
|
||||
thicknessColor?: string | number
|
||||
thicknessDistortion?: number
|
||||
thicknessAmbient?: number
|
||||
thicknessAttenuation?: number
|
||||
thicknessPower?: number
|
||||
thicknessScale?: number
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props,
|
||||
props: {
|
||||
uniforms: { type: Object as PropType<SubSurfaceMaterialUniformsInterface>, default: () => ({
|
||||
diffuse: '#ffffff',
|
||||
thicknessColor: '#ffffff',
|
||||
thicknessDistortion: 0.4,
|
||||
thicknessAmbient: 0.01,
|
||||
thicknessAttenuation: 0.7,
|
||||
thicknessPower: 2,
|
||||
thicknessScale: 4,
|
||||
}) },
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const params = SubsurfaceScatteringShader
|
||||
const uniforms = UniformsUtils.clone(params.uniforms)
|
||||
|
||||
Object.keys(props).forEach((key) => {
|
||||
// @ts-ignore
|
||||
const value = this[key]
|
||||
let _key = key, _value = value
|
||||
if (['color', 'thicknessColor'].includes(key)) {
|
||||
if (key === 'color') _key = 'diffuse'
|
||||
_value = new Color(value)
|
||||
}
|
||||
uniforms[_key].value = _value
|
||||
bindObjectProp(this, 'uniforms', uniforms, true, (dst: any, key: string, value: any) => {
|
||||
const dstVal = dst[key].value
|
||||
if (dstVal instanceof Color) dstVal.set(value)
|
||||
else dst[key].value = value
|
||||
})
|
||||
|
||||
const material = new ShaderMaterial({
|
||||
...params,
|
||||
uniforms,
|
||||
lights: true,
|
||||
transparent: this.transparent,
|
||||
vertexColors: this.vertexColors,
|
||||
...this.props,
|
||||
uniforms,
|
||||
})
|
||||
|
||||
return material
|
||||
},
|
||||
},
|
||||
__hmrId: 'SubSurfaceMaterial',
|
||||
})
|
||||
|
@ -1,19 +0,0 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { MeshToonMaterial } from 'three'
|
||||
import { bindProps, propsValues } from '../tools'
|
||||
import Material, { wireframeProps } from './Material'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Material,
|
||||
props: {
|
||||
...wireframeProps,
|
||||
},
|
||||
methods: {
|
||||
createMaterial() {
|
||||
const material = new MeshToonMaterial(propsValues(this.$props))
|
||||
bindProps(this, Object.keys(wireframeProps), material)
|
||||
return material
|
||||
},
|
||||
},
|
||||
__hmrId: 'ToonMaterial',
|
||||
})
|
@ -1,17 +1,9 @@
|
||||
export { default as Material, MaterialInjectionKey } from './Material'
|
||||
export { default as BasicMaterial } from './BasicMaterial'
|
||||
export { default as LambertMaterial } from './LambertMaterial'
|
||||
export { default as Material, BasicMaterial, LambertMaterial, PhongMaterial, PhysicalMaterial, PointsMaterial, StandardMaterial, ToonMaterial, MaterialInjectionKey } from './Material'
|
||||
export { default as MatcapMaterial } from './MatcapMaterial'
|
||||
export { default as PhongMaterial } from './PhongMaterial'
|
||||
export { default as PhysicalMaterial } from './PhysicalMaterial'
|
||||
export { default as ShaderMaterial } from './ShaderMaterial'
|
||||
export { default as StandardMaterial } from './StandardMaterial'
|
||||
export { default as SubSurfaceMaterial } from './SubSurfaceMaterial'
|
||||
export { default as ToonMaterial } from './ToonMaterial'
|
||||
|
||||
export { default as Texture } from './Texture'
|
||||
export { default as CubeTexture } from './CubeTexture'
|
||||
|
||||
export { default as PointsMaterial } from './PointsMaterial'
|
||||
|
||||
export type { MaterialPublicInterface } from './Material'
|
||||
|
@ -19,9 +19,10 @@ export function bindObjectProp(
|
||||
src: any,
|
||||
prop: string,
|
||||
dst: any,
|
||||
apply = true,
|
||||
setter?: OptionSetter
|
||||
): WatchStopHandle {
|
||||
applyObjectProps(dst, src[prop], setter)
|
||||
if (apply) applyObjectProps(dst, src[prop], setter)
|
||||
const r = toRef(src, prop)
|
||||
return watch(r, (value) => { applyObjectProps(dst, value, setter) })
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user