UNPKG

polygonjs-engine

Version:

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

210 lines (199 loc) 7.01 kB
/** * Creates a Mesh Subsurface Scattering Material * * @remarks * This material needs lights to be visible. * */ import {ShaderMaterial} from 'three/src/materials/ShaderMaterial'; import {TypedMatNode} from './_Base'; import {SubsurfaceScatteringShader} from '../../../modules/three/examples/jsm/shaders/SubsurfaceScatteringShader'; import {SideController, SideParamConfig} from './utils/SideController'; import {SkinningController, SkinningParamConfig} from './utils/SkinningController'; import {TextureMapController, TextureMapParamConfig} from './utils/TextureMapController'; import {UniformsUtils} from 'three/src/renderers/shaders/UniformsUtils'; import {TextureAlphaMapController, TextureAlphaMapParamConfig} from './utils/TextureAlphaMapController'; function ParamOptionsFactoryColor(uniform_name: string) { return { cook: false, callback: (node: BaseNodeType, param: BaseParamType) => { MeshSubsurfaceScatteringMatNode.PARAM_CALLBACK_update_uniformColor( node as MeshSubsurfaceScatteringMatNode, param, uniform_name ); }, }; } function ParamOptionsFactoryTexture(uniform_name: string) { return { cook: false, callback: (node: BaseNodeType, param: BaseParamType) => { MeshSubsurfaceScatteringMatNode.PARAM_CALLBACK_update_uniformTexture( node as MeshSubsurfaceScatteringMatNode, param, uniform_name ); }, }; } function ParamOptionsFactoryN(uniform_name: string) { return { cook: false, callback: (node: BaseNodeType, param: BaseParamType) => { MeshSubsurfaceScatteringMatNode.PARAM_CALLBACK_update_uniformN( node as MeshSubsurfaceScatteringMatNode, param, uniform_name ); }, }; } import {BaseNodeType} from '../_Base'; import {BaseParamType} from '../../params/_Base'; import {IUniformN, IUniformTexture, IUniformColor} from '../utils/code/gl/Uniforms'; import {IUniform} from 'three/src/renderers/shaders/UniformsLib'; import {NodeContext} from '../../poly/NodeContext'; import {BaseCopNodeType} from '../cop/_Base'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {OperatorPathParam} from '../../params/OperatorPath'; import {NODE_PATH_DEFAULT} from '../../../core/Walker'; class MeshSubsurfaceScatteringMatParamsConfig extends TextureMapParamConfig( TextureAlphaMapParamConfig(SkinningParamConfig(SideParamConfig(NodeParamsConfig))) ) { diffuse = ParamConfig.COLOR([1, 1, 1], { ...ParamOptionsFactoryColor('diffuse'), }); shininess = ParamConfig.FLOAT(1, { range: [0, 1000], }); thicknessMap = ParamConfig.OPERATOR_PATH(NODE_PATH_DEFAULT.NODE.UV, { nodeSelection: {context: NodeContext.COP}, ...ParamOptionsFactoryTexture('thicknessMap'), }); thicknessColor = ParamConfig.COLOR([0.5, 0.3, 0.0], { ...ParamOptionsFactoryColor('thicknessColor'), }); thicknessDistortion = ParamConfig.FLOAT(0.1, { ...ParamOptionsFactoryN('thicknessDistortion'), }); thicknessAmbient = ParamConfig.FLOAT(0.4, { ...ParamOptionsFactoryN('thicknessAmbient'), }); thicknessAttenuation = ParamConfig.FLOAT(0.8, { ...ParamOptionsFactoryN('thicknessAttenuation'), }); thicknessPower = ParamConfig.FLOAT(2.0, { range: [0, 10], ...ParamOptionsFactoryN('thicknessPower'), }); thicknessScale = ParamConfig.FLOAT(16.0, { range: [0, 100], ...ParamOptionsFactoryN('thicknessScale'), }); } const ParamsConfig = new MeshSubsurfaceScatteringMatParamsConfig(); interface ShaderMaterialWithUniforms extends ShaderMaterial { uniforms: { diffuse: IUniformColor; shininess: IUniformN; thicknessMap: IUniformTexture; thicknessColor: IUniformColor; thicknessDistortion: IUniformN; thicknessAmbient: IUniformN; thicknessAttenuation: IUniformN; thicknessPower: IUniformN; thicknessScale: IUniformN; [uniform: string]: IUniform; }; } export class MeshSubsurfaceScatteringMatNode extends TypedMatNode< ShaderMaterialWithUniforms, MeshSubsurfaceScatteringMatParamsConfig > { params_config = ParamsConfig; static type() { return 'meshSubsurfaceScattering'; } create_material() { const uniforms = UniformsUtils.clone(SubsurfaceScatteringShader.uniforms); const material: ShaderMaterialWithUniforms = new ShaderMaterial({ uniforms: uniforms, vertexShader: SubsurfaceScatteringShader.vertexShader, fragmentShader: SubsurfaceScatteringShader.fragmentShader, lights: true, }) as ShaderMaterialWithUniforms; material.extensions.derivatives = true; return material; } readonly texture_map_controller: TextureMapController = new TextureMapController(this, { uniforms: true, // define: false, // define_uv: false, }); readonly texture_alpha_map_controller: TextureAlphaMapController = new TextureAlphaMapController(this, { uniforms: true, // define: false, // define_uv: false, }); initializeNode() { this.params.onParamsCreated('init controllers', () => { this.texture_map_controller.initializeNode(); this.texture_alpha_map_controller.initializeNode(); }); } async cook() { SideController.update(this); SkinningController.update(this); this.texture_map_controller.update(); this.texture_alpha_map_controller.update(); this.update_map(this.p.thicknessMap, 'thicknessMap'); this.material.uniforms.diffuse.value.copy(this.pv.diffuse); this.material.uniforms.shininess.value = this.pv.shininess; this.material.uniforms.thicknessColor.value.copy(this.pv.thicknessColor); this.material.uniforms.thicknessDistortion.value = this.pv.thicknessDistortion; this.material.uniforms.thicknessAmbient.value = this.pv.thicknessAmbient; this.material.uniforms.thicknessAttenuation.value = this.pv.thicknessAttenuation; this.material.uniforms.thicknessPower.value = this.pv.thicknessPower; this.material.uniforms.thicknessScale.value = this.pv.thicknessScale; this.set_material(this.material); } // static PARAM_CALLBACK_update_thickness_map(node: MeshTranslucentMatNode) { // node.update_thickness_map(); // } static PARAM_CALLBACK_update_uniformN( node: MeshSubsurfaceScatteringMatNode, param: BaseParamType, uniform_name: string ) { node.material.uniforms[uniform_name].value = param.value; } static PARAM_CALLBACK_update_uniformColor( node: MeshSubsurfaceScatteringMatNode, param: BaseParamType, uniform_name: string ) { if (param.parent_param) { node.material.uniforms[uniform_name].value.copy(param.parent_param.value); } } static PARAM_CALLBACK_update_uniformTexture( node: MeshSubsurfaceScatteringMatNode, param: BaseParamType, uniform_name: string ) { node.update_map(param as OperatorPathParam, uniform_name); } async update_map(param: OperatorPathParam, uniform_name: string) { const node = param.found_node(); if (node) { if (node.nodeContext() == NodeContext.COP) { const texture_node = node as BaseCopNodeType; const container = await texture_node.requestContainer(); this.material.uniforms[uniform_name].value = container.texture(); return; } } this.material.uniforms[uniform_name].value = null; } }