UNPKG

@polygonjs/polygonjs

Version:

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

155 lines (154 loc) 5.72 kB
"use strict"; import { BaseSopOperation } from "./_Base"; import { TypedNodePathParamValue } from "../../../core/Walker"; import { NodeContext } from "../../../engine/poly/NodeContext"; import { applyRenderHook, applyCustomMaterials, cloneMaterial } from "../../../core/geometry/Material"; import { ShaderMaterial } from "three"; import { GlobalsGeometryHandler } from "../../../engine/nodes/gl/code/globals/Geometry"; import { InputCloneMode } from "../../../engine/poly/InputCloneMode"; import { isBooleanTrue } from "../../../core/BooleanValue"; import { CoreMask } from "../../../core/geometry/Mask"; let _nextId = 0; export class MaterialSopOperation extends BaseSopOperation { constructor() { super(...arguments); this._materialSopOperationId = _nextId++; this._globalsHandler = new GlobalsGeometryHandler(); this._onMaterialUpdateBound = this._onMaterialUpdate.bind(this); this._oldMatByOldNewId = /* @__PURE__ */ new Map(); this._materialByUuid = /* @__PURE__ */ new Map(); } static type() { return "material"; } async cook(inputCoreGroups, params) { const coreGroup = inputCoreGroups[0]; this._oldMatByOldNewId.clear(); await this._applyMaterials(coreGroup, params); this._swapTextures(coreGroup, params); return coreGroup; } async _getMaterial(params) { var _a, _b, _c, _d; const materialNode = params.material.nodeWithContext(NodeContext.MAT, (_a = this.states) == null ? void 0 : _a.error); if (materialNode) { this._watchMaterialNode(materialNode); const material = await materialNode.material(); const baseBuilderMatNode = materialNode; if (baseBuilderMatNode.assemblerController) { (_b = baseBuilderMatNode.assemblerController()) == null ? void 0 : _b.setAssemblerGlobalsHandler(this._globalsHandler); } if (!material) { (_c = this.states) == null ? void 0 : _c.error.set(`material invalid. (error: '${materialNode.states.error.message()}')`); } return material; } else { (_d = this.states) == null ? void 0 : _d.error.set(`no material node found`); } } _watchMaterialNode(materialNode) { if (this._watchedMaterialNode == materialNode) { return; } const hookName = this._watchHookName(); materialNode.addPostDirtyHook(hookName, this._onMaterialUpdateBound); materialNode.cookController.registerOnCookEnd(hookName, this._onMaterialUpdateBound); if (this._watchedMaterialNode) { this._watchedMaterialNode.removePostDirtyHook(hookName); this._watchedMaterialNode.cookController.deregisterOnCookEnd(hookName); } this._watchedMaterialNode = materialNode; } async _onMaterialUpdate() { if (!this._watchedMaterialNode) { return; } const container = await this._watchedMaterialNode.compute(); const material = container.material(); if (material != this._watchedMaterialNodeMaterial) { this._watchedMaterialNodeMaterial = material; if (this._node) { this._node.p.material.setDirty(); } } } _watchHookName() { return `MaterialSopOperationId-${this._materialSopOperationId}`; } async _applyMaterials(coreGroup, params) { if (!isBooleanTrue(params.assignMat)) { return; } const material = await this._getMaterial(params); if (!material) { return; } const selectedObjects = CoreMask.filterThreejsObjects(coreGroup, params); for (let selectedObject of selectedObjects) { this._applyMaterial(selectedObject, material, params); } return coreGroup; } _swapTextures(coreGroup, params) { if (!isBooleanTrue(params.swapCurrentTex)) { return; } this._materialByUuid.clear(); const objects = CoreMask.filterObjects(coreGroup, params, coreGroup.allCoreObjects()); for (let object of objects) { const mat = object.material; this._materialByUuid.set(mat.uuid, mat); } this._materialByUuid.forEach((mat, mat_uuid) => { this._swapTexture(mat, params); }); } _applyMaterial(object, srcMaterial, params) { const usedMaterial = isBooleanTrue(params.cloneMat) ? cloneMaterial(this.scene(), srcMaterial, { shareCustomUniforms: params.shareCustomUniforms, addCustomMaterials: true }) : srcMaterial; if (srcMaterial instanceof ShaderMaterial && usedMaterial instanceof ShaderMaterial) { for (let uniform_name in srcMaterial.uniforms) { usedMaterial.uniforms[uniform_name] = srcMaterial.uniforms[uniform_name]; } } if (object.isGroup) { return; } const object_with_material = object; this._oldMatByOldNewId.set(usedMaterial.uuid, object_with_material.material); object_with_material.material = usedMaterial; applyRenderHook(object, usedMaterial); applyCustomMaterials(object, usedMaterial); } _swapTexture(target_mat, params) { if (params.texSrc0 == "" || params.texDest0 == "") { return; } let src_mat = this._oldMatByOldNewId.get(target_mat.uuid); src_mat = src_mat || target_mat; const src_tex = src_mat[params.texSrc0]; if (src_tex) { target_mat[params.texDest0] = src_tex; const uniforms = target_mat.uniforms; if (uniforms) { const uniforms_map = uniforms[params.texDest0]; if (uniforms_map) { uniforms[params.texDest0] = { value: src_tex }; } } } } } MaterialSopOperation.DEFAULT_PARAMS = { group: "", assignMat: true, material: new TypedNodePathParamValue(""), cloneMat: false, shareCustomUniforms: true, swapCurrentTex: false, texSrc0: "emissiveMap", texDest0: "map" }; MaterialSopOperation.INPUT_CLONED_STATE = InputCloneMode.FROM_NODE;