UNPKG

@polygonjs/polygonjs

Version:

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

194 lines (177 loc) 5.86 kB
/** * generates a cube map from a scene * * */ import {Constructor, valueof} from '../../../types/GlobalTypes'; import {TypedCopNode} from './_Base'; import {GeoNodeChildrenMap} from '../../poly/registers/nodes/Sop'; import {BaseGlNodeType} from '../gl/_Base'; import {NodeContext} from '../../poly/NodeContext'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {NodeCreateOptions} from '../utils/hierarchy/ChildrenController'; import {BaseNodeType} from '../_Base'; import {CopType} from '../../poly/registers/nodes/types/Cop'; import {DisplayNodeController} from '../utils/DisplayNodeController'; import {PMREMGenerator, Scene, Texture, WebGLRenderer, WebGLRenderTarget} from 'three'; import {BaseSopNodeType} from '../sop/_Base'; import {CopRendererController} from './utils/RendererController'; function CubeMapFromSceneCopParamConfig<TBase extends Constructor>(Base: TBase) { return class Mixin extends Base { /** @param force Render */ blur = ParamConfig.FLOAT(0, { range: [0, 0.1], step: 0.0001, rangeLocked: [true, false], }); /** @param camera near */ near = ParamConfig.FLOAT(0.1, { range: [0.0001, 1], step: 0.0001, rangeLocked: [true, false], }); /** @param camera far */ far = ParamConfig.FLOAT(100, { range: [0, 100], rangeLocked: [true, false], }); /** @param force Render */ render = ParamConfig.BUTTON(null, { callback: async (node: BaseNodeType) => { await CubeMapFromSceneCopNode.PARAM_CALLBACK_render(node as CubeMapFromSceneCopNode); }, }); }; } class CubeMapFromSceneCopParamsConfig extends CubeMapFromSceneCopParamConfig(NodeParamsConfig) {} const ParamsConfig = new CubeMapFromSceneCopParamsConfig(); export class CubeMapFromSceneCopNode extends TypedCopNode<CubeMapFromSceneCopParamsConfig> { override paramsConfig = ParamsConfig; static override type() { return CopType.CUBE_MAP_FROM_SCENE; } private _rendererController: CopRendererController | undefined; private _lastGeneratedRenderTarget: WebGLRenderTarget | undefined; lastGeneratedRenderTarget() { return this._lastGeneratedRenderTarget; } // display_node and children_display controllers // private _renderCubeMapBound = this._renderCubeMap.bind(this); private _setDirtyBound = this._setDirty.bind(this); public override readonly displayNodeController: DisplayNodeController = new DisplayNodeController(this, { onDisplayNodeRemove: this._setDirtyBound, onDisplayNodeSet: this._setDirtyBound, onDisplayNodeUpdate: this._setDirtyBound, }); // protected override _childrenControllerContext = NodeContext.SOP; override initializeNode() { this.addPostDirtyHook('_cook_main_without_inputs_when_dirty', () => { setTimeout(this._cookMainWithoutInputsWhenDirtyBound, 0); }); } override dispose() { this._pmremGenerator?.dispose(); super.dispose(); } override createNode<S extends keyof GeoNodeChildrenMap>( node_class: S, options?: NodeCreateOptions ): GeoNodeChildrenMap[S]; override createNode<K extends valueof<GeoNodeChildrenMap>>( node_class: Constructor<K>, options?: NodeCreateOptions ): K; override createNode<K extends valueof<GeoNodeChildrenMap>>( node_class: Constructor<K>, options?: NodeCreateOptions ): K { return super.createNode(node_class, options) as K; } override children() { return super.children() as BaseGlNodeType[]; } override nodesByType<K extends keyof GeoNodeChildrenMap>(type: K): GeoNodeChildrenMap[K][] { return super.nodesByType(type) as GeoNodeChildrenMap[K][]; } override childrenAllowed() { return true; } private _setDirty() { this.setDirty(); } private _cookMainWithoutInputsWhenDirtyBound = this._cookMainWithoutInputsWhenDirty.bind(this); private async _cookMainWithoutInputsWhenDirty() { await this.cookController.cookMainWithoutInputs(); } override async cook() { await this._updateRenderScene(); const texture = await this._renderCubeMap(); if (!texture) { this.cookController.endCook(); } } private _renderScene = new Scene(); private _pmremGenerator: PMREMGenerator | undefined; private async _updateRenderScene() { if (!this.scene().loadingController.autoUpdating()) { return; } const displayNode = this.displayNodeController.displayNode(); if (!displayNode) { return; } if (displayNode.context() != NodeContext.SOP) { return; } const sopNode = displayNode as BaseSopNodeType; const container = await sopNode.compute(); if (!container) { return; } const coreGroup = container.coreContent(); if (!coreGroup) { return; } const currentChildren = [...this._renderScene.children]; for (const child of currentChildren) { this._renderScene.remove(child); } const objects = coreGroup.threejsObjects(); for (const object of objects) { this._renderScene.add(object); } } private async _renderCubeMap(): Promise<Texture | undefined> { if (!this.scene().loadingController.autoUpdating()) { return; } this._rendererController = this._rendererController || new CopRendererController(this); const renderer = await this._rendererController.waitForRenderer(); if (!renderer) { this.states.error.set('no renderer found to convert the texture to an env map'); return; } if (!(renderer instanceof WebGLRenderer)) { this.states.error.set('found renderer is not a WebGLRenderer'); return; } this._pmremGenerator = this._pmremGenerator || new PMREMGenerator(renderer); this._lastGeneratedRenderTarget = this._pmremGenerator.fromScene( this._renderScene, this.pv.blur, this.pv.near, this.pv.far ); this.setTexture(this._lastGeneratedRenderTarget.texture); return this._lastGeneratedRenderTarget.texture; } /* * * CALLBACK * */ static async PARAM_CALLBACK_render(node: CubeMapFromSceneCopNode) { await node._renderCubeMap(); } }