lume
Version:
155 lines (140 loc) • 4.71 kB
text/typescript
import 'element-behaviors'
import {MeshStandardMaterial} from 'three/src/materials/MeshStandardMaterial.js'
import {booleanAttribute, numberAttribute, stringAttribute} from '@lume/element'
import {behavior} from '../../Behavior.js'
import {receiver} from '../../PropReceiver.js'
import {MaterialBehavior, type MaterialBehaviorAttributes} from './MaterialBehavior.js'
export type StandardMaterialBehaviorAttributes =
| MaterialBehaviorAttributes
| 'alphaMap'
| 'aoMap'
| 'aoMapIntensity'
| 'bumpMap'
| 'bumpScale'
| 'displacementMap'
| 'displacementScale'
| 'displacementBias'
| 'texture' // map
| 'normalMap'
| 'normalScale'
| 'metalness'
| 'metalnessMap'
| 'morphNormals'
| 'morphTargets'
| 'roughness'
| 'roughnessMap'
| 'vertexTangents'
/**
* @class StandardMaterialBehavior -
*
* A standard physically based material, using Metallic-Roughness workflow.
*
* Backed by Three.js [`THREE.MeshStandardMaterial`](https://threejs.org/docs/index.html#api/en/materials/MeshStandardMaterial)
*
* @extends MaterialBehavior
*/
export
class StandardMaterialBehavior extends MaterialBehavior {
alphaMap = ''
aoMap = ''
aoMapIntensity = 1
bumpMap = ''
bumpScale = 1
displacementMap = ''
displacementScale = 1
displacementBias = 0
// emissive?: Color | string | number;
// envMap?: Texture | null;
// @numberAttribute @receiver envMapIntensity?: number
// @numberAttribute @receiver emissiveIntensity?: number
// emissiveMap?: Texture | null;
// lightMap?: Texture | null;
// @numberAttribute @receiver lightMapIntensity?: number
texture = '' // map
normalMap = ''
// normalMapType
normalScale = 1
metalness = 0
metalnessMap = ''
// @numberAttribute @receiver refractionRatio?: number
roughness = 1
roughnessMap = ''
// wireframe?: boolean
// @numberAttribute @receiver wireframeLinewidth?: number // Not supported because the WebGL line width is always 1.
// @booleanAttribute @receiver skinning: boolean = false
vertexTangents: boolean = false
morphTargets: boolean = false
morphNormals: boolean = false
override _createComponent() {
return new MeshStandardMaterial()
}
override connectedCallback() {
super.connectedCallback()
this.createEffect(() => {
const mat = this.meshComponent
if (!mat) return
mat.aoMapIntensity = this.aoMapIntensity
mat.bumpScale = this.bumpScale
mat.displacementScale = this.displacementScale
mat.displacementBias = this.displacementBias
mat.normalScale.set(this.normalScale, this.normalScale)
mat.metalness = this.metalness
// mat.morphNormals = this.morphNormals
// mat.morphTargets = this.morphTargets
mat.roughness = this.roughness
// mat.vertexTangents = this.vertexTangents
// TODO Needed?
// mat.needsUpdate = true
this.element.needsUpdate()
})
this._handleTexture(
() => this.alphaMap,
(mat, tex) => (mat.alphaMap = tex),
mat => !!mat.alphaMap,
)
this._handleTexture(
() => this.aoMap,
(mat, tex) => (mat.aoMap = tex),
mat => !!mat.aoMap,
)
this._handleTexture(
() => this.bumpMap,
(mat, tex) => (mat.bumpMap = tex),
mat => !!mat.bumpMap,
)
this._handleTexture(
() => this.displacementMap,
(mat, tex) => (mat.displacementMap = tex),
mat => !!mat.displacementMap,
)
this._handleTexture(
() => this.texture, // map
(mat, tex) => (mat.map = tex),
mat => !!mat.map,
() => {},
true,
)
this._handleTexture(
() => this.normalMap,
(mat, tex) => (mat.normalMap = tex),
mat => !!mat.normalMap,
)
this._handleTexture(
() => this.metalnessMap,
(mat, tex) => (mat.metalnessMap = tex),
mat => !!mat.metalnessMap,
)
this._handleTexture(
() => this.roughnessMap,
(mat, tex) => (mat.roughnessMap = tex),
mat => !!mat.roughnessMap,
)
}
}
if (globalThis.window?.document && !elementBehaviors.has('standard-material'))
elementBehaviors.define('standard-material', StandardMaterialBehavior)
// This prevents errors with mixins. https://discord.com/channels/508357248330760243/508357248330760249/954526657312604180
export type MixinBaseClass<T> = T extends new (..._: any) => infer I
? {[K in keyof T]: T[K]} & (new (...args: any[]) => I)
: new (...args: any[]) => T