UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

129 lines (124 loc) 4.72 kB
import {Constructor, Number2} from '../../../../types/GlobalTypes'; import {TypedMatNode} from '../_Base'; import {BaseTextureMapController, BooleanParamOptions, NodePathOptions} from './_BaseTextureController'; import {NodeParamsConfig, ParamConfig} from '../../utils/params/ParamsConfig'; import {TangentSpaceNormalMap, ObjectSpaceNormalMap, Material} from 'three'; import {MeshPhysicalMaterial} from 'three'; import {MeshStandardMaterial} from 'three'; import {MeshPhongMaterial} from 'three'; import {MeshMatcapMaterial} from 'three'; import {MeshNormalMaterial} from 'three'; import {MeshToonMaterial} from 'three'; import {MaterialTexturesRecord, SetParamsTextureNodesRecord} from './_BaseController'; enum NormalMapMode { TANGENT = 'tangent', OBJECT = 'object', } const NORMAL_MAP_MODES: NormalMapMode[] = [NormalMapMode.TANGENT, NormalMapMode.OBJECT]; const NormalMapModeByName = { [NormalMapMode.TANGENT]: TangentSpaceNormalMap, [NormalMapMode.OBJECT]: ObjectSpaceNormalMap, }; const NormalNameByMode = { [TangentSpaceNormalMap]: NormalMapMode.TANGENT, [ObjectSpaceNormalMap]: NormalMapMode.OBJECT, }; export function NormalMapParamConfig<TBase extends Constructor>(Base: TBase) { return class Mixin extends Base { /** @param toggle if you want to use a normal map */ useNormalMap = ParamConfig.BOOLEAN(0, { separatorBefore: true, ...BooleanParamOptions(TextureNormalMapController), }); /** @param specify the normal map COP node */ normalMap = ParamConfig.NODE_PATH('', NodePathOptions(TextureNormalMapController, 'useNormalMap')); /** @param type of normal map being used */ normalMapType = ParamConfig.INTEGER(0, { visibleIf: {useNormalMap: 1}, menu: { entries: NORMAL_MAP_MODES.map((name, value) => { return {name, value}; }), }, }); /** @param How much the normal map affects the material. Typical ranges are 0-1 */ normalScale = ParamConfig.VECTOR2([1, 1], {visibleIf: {useNormalMap: 1}}); /** @param Normal Map Scale Multiplier, which multiples normalScale */ normalScaleMult = ParamConfig.FLOAT(1, { range: [0, 1], rangeLocked: [false, false], visibleIf: {useNormalMap: 1}, }); }; } type TextureNormalMapControllerCurrentMaterial = | MeshPhongMaterial | MeshNormalMaterial | MeshMatcapMaterial | MeshPhysicalMaterial | MeshToonMaterial | MeshStandardMaterial; function isTextureNormalMapMaterial(material?: Material): material is TextureNormalMapControllerCurrentMaterial { if (!material) { return false; } return (material as MeshNormalMaterial as any).normalScale != null; } class TextureNormalMapParamsConfig extends NormalMapParamConfig(NodeParamsConfig) {} export interface TextureNormalMapControllers { normalMap: TextureNormalMapController; } abstract class TextureNormalMapMatNode extends TypedMatNode< TextureNormalMapControllerCurrentMaterial, TextureNormalMapParamsConfig > { controllers!: TextureNormalMapControllers; async material() { const container = await this.compute(); return container.material() as TextureNormalMapControllerCurrentMaterial | undefined; } } const tmpN2: Number2 = [0, 0]; export class TextureNormalMapController extends BaseTextureMapController { constructor(protected override node: TextureNormalMapMatNode) { super(node); } override initializeNode() { this.add_hooks(this.node.p.useNormalMap, this.node.p.normalMap); } static override async update(node: TextureNormalMapMatNode) { node.controllers.normalMap.update(); } override async update() { const material = await this.node.material(); if (!isTextureNormalMapMaterial(material)) { return; } await this.updateMaterial(material); } override async updateMaterial(material: TextureNormalMapControllerCurrentMaterial) { const {p, pv} = this.node; await this._update(material, 'normalMap', p.useNormalMap, p.normalMap); const normalMapType = NormalMapModeByName[NORMAL_MAP_MODES[pv.normalMapType]]; const mat = material as MeshPhongMaterial; mat.normalMapType = normalMapType; mat.normalScale.copy(pv.normalScale).multiplyScalar(pv.normalScaleMult); } override getTextures(material: TextureNormalMapControllerCurrentMaterial, record: MaterialTexturesRecord) { record.set('normalMap', material.normalMap); } override setParamsFromMaterial( material: TextureNormalMapControllerCurrentMaterial, record: SetParamsTextureNodesRecord ) { const mapNode = record.get('normalMap'); const p = this.node.p; p.useNormalMap.set(mapNode != null); if (mapNode) { p.normalMap.setNode(mapNode, {relative: true}); } material.normalScale.toArray(tmpN2); p.normalScale.set(tmpN2); p.normalMapType.set(NORMAL_MAP_MODES.indexOf(NormalNameByMode[material.normalMapType])); } }