UNPKG

polygonjs-engine

Version:

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

276 lines (256 loc) 7.89 kB
/** * Creates a THREE.Scene. * * @remarks * By default, all objects created will be added under the same master scene. This is enough in most cases, but there might be times where you want to use a custom one. For instance: * * - you would like to change the background color or the environment. * - you would like to have a fog. * - You may also use multiple scenes, if you want to switch from one to the other. * * For those situtation, you can parent the objects under a scene node, and set your camera scene parameter to point to it. The camera will then render this scene instead of the master one. * * */ import {TypedObjNode} from './_Base'; import {Scene} from 'three/src/scenes/Scene'; import {Fog} from 'three/src/scenes/Fog'; import {FogExp2} from 'three/src/scenes/FogExp2'; import {NodeContext} from '../../poly/NodeContext'; import {BaseCopNodeType} from '../cop/_Base'; import {BaseMatNodeType} from '../mat/_Base'; import {HierarchyController} from './utils/HierarchyController'; enum BackgroundMode { NONE = 'none', COLOR = 'color', TEXTURE = 'texture', } const BACKGROUND_MODES: BackgroundMode[] = [BackgroundMode.NONE, BackgroundMode.COLOR, BackgroundMode.TEXTURE]; enum FogType { LINEAR = 'linear', EXPONENTIAL = 'exponential', } const FOG_TYPES: FogType[] = [FogType.LINEAR, FogType.EXPONENTIAL]; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; class SceneObjParamConfig extends NodeParamsConfig { /** @param autoUpdate */ autoUpdate = ParamConfig.BOOLEAN(1); // background /** @param set background mode (none, color or texture) */ backgroundMode = ParamConfig.INTEGER(BACKGROUND_MODES.indexOf(BackgroundMode.NONE), { menu: { entries: BACKGROUND_MODES.map((mode, i) => { return {name: mode, value: i}; }), }, }); /** @param background color */ bgColor = ParamConfig.COLOR([0, 0, 0], { visibleIf: {backgroundMode: BACKGROUND_MODES.indexOf(BackgroundMode.COLOR)}, }); /** @param background texture */ bgTexture = ParamConfig.OPERATOR_PATH('', { visibleIf: {backgroundMode: BACKGROUND_MODES.indexOf(BackgroundMode.TEXTURE)}, nodeSelection: { context: NodeContext.COP, }, dependentOnFoundNode: false, }); // environment /** @param toggle on to use an environment map */ useEnvironment = ParamConfig.BOOLEAN(0); /** @param environment map */ environment = ParamConfig.OPERATOR_PATH('', { visibleIf: {useEnvironment: 1}, nodeSelection: { context: NodeContext.COP, }, dependentOnFoundNode: false, }); // fog /** @param toggle on to use fog */ useFog = ParamConfig.BOOLEAN(0); /** @param fog type */ fogType = ParamConfig.INTEGER(FOG_TYPES.indexOf(FogType.EXPONENTIAL), { visibleIf: {useFog: 1}, menu: { entries: FOG_TYPES.map((mode, i) => { return {name: mode, value: i}; }), }, }); /** @param fog color */ fogColor = ParamConfig.COLOR([1, 1, 1], {visibleIf: {useFog: 1}}); /** @param fog near */ fogNear = ParamConfig.FLOAT(1, { range: [0, 100], rangeLocked: [true, false], visibleIf: {useFog: 1, fogType: FOG_TYPES.indexOf(FogType.LINEAR)}, }); /** @param fog far */ fogFar = ParamConfig.FLOAT(100, { range: [0, 100], rangeLocked: [true, false], visibleIf: {useFog: 1, fogType: FOG_TYPES.indexOf(FogType.LINEAR)}, }); /** @param fog density */ fogDensity = ParamConfig.FLOAT(0.00025, { visibleIf: {useFog: 1, fogType: FOG_TYPES.indexOf(FogType.EXPONENTIAL)}, }); // override material /** @param toggle on to override all materials */ useOverrideMaterial = ParamConfig.BOOLEAN(0); /** @param material */ overrideMaterial = ParamConfig.OPERATOR_PATH('/MAT/mesh_standard1', { visibleIf: {useOverrideMaterial: 1}, nodeSelection: { context: NodeContext.MAT, }, dependentOnFoundNode: false, }); } const ParamsConfig = new SceneObjParamConfig(); export class SceneObjNode extends TypedObjNode<Scene, SceneObjParamConfig> { params_config = ParamsConfig; static type(): Readonly<'scene'> { return 'scene'; } // protected _attachable_to_hierarchy: boolean = false; readonly hierarchy_controller: HierarchyController = new HierarchyController(this); private _fog: Fog | undefined; private _fog_exp2: FogExp2 | undefined; create_object() { const scene = new Scene(); scene.matrixAutoUpdate = false; return scene; } initializeNode() { // this.dirtyController.addPostDirtyHook( // '_cook_main_without_inputs_when_dirty', // this._cook_main_without_inputs_when_dirty_bound // ); // super.initializeNode(); this.hierarchy_controller.initializeNode(); // this.io.outputs.set_has_one_output(); } // TODO: I may be able to swap those methods to param callbacks for most params // private _cook_main_without_inputs_when_dirty_bound = this._cook_main_without_inputs_when_dirty.bind(this); // private async _cook_main_without_inputs_when_dirty() { // // if (this.used_in_scene) { // await this.cookController.cook_main_without_inputs(); // // } // } cook() { if (this.pv.autoUpdate != this.object.autoUpdate) { this.object.autoUpdate = this.pv.autoUpdate; } this._update_background(); this._update_fog(); this._update_enviromment(); this._update_material_override(); this.cookController.end_cook(); } // // // BACKGROUND // // private _update_background() { if (this.pv.backgroundMode == BACKGROUND_MODES.indexOf(BackgroundMode.NONE)) { this.object.background = null; } else { if (this.pv.backgroundMode == BACKGROUND_MODES.indexOf(BackgroundMode.COLOR)) { this.object.background = this.pv.bgColor; } else { const node = this.p.bgTexture.found_node(); if (node) { if (node.nodeContext() == NodeContext.COP) { (node as BaseCopNodeType).requestContainer().then((container) => { this.object.background = container.texture(); }); } else { this.states.error.set('bgTexture node is not a texture'); } } else { this.states.error.set('bgTexture node not found'); } } } } // // // FOG // // private _update_fog() { if (this.pv.useFog) { if (this.pv.fogType == FOG_TYPES.indexOf(FogType.LINEAR)) { this.object.fog = this.fog; this.fog.color = this.pv.fogColor; this.fog.near = this.pv.fogNear; this.fog.far = this.pv.fogFar; } else { this.object.fog = this.fog_exp2; this.fog_exp2.color = this.pv.fogColor; this.fog_exp2.density = this.pv.fogDensity; } } else { const current_fog = this.object.fog; if (current_fog) { this.object.fog = null; } } } get fog() { return (this._fog = this._fog || new Fog(0xffffff, this.pv.fogNear, this.pv.fogFar)); } get fog_exp2() { return (this._fog_exp2 = this._fog_exp2 || new FogExp2(0xffffff, this.pv.fogDensity)); } // // // ENVIRONMENT // // private _update_enviromment() { if (this.pv.useEnvironment) { const node = this.p.environment.found_node(); if (node) { if (node.nodeContext() == NodeContext.COP) { (node as BaseCopNodeType).requestContainer().then((container) => { this.object.environment = container.texture(); }); } else { this.states.error.set('bgTexture node is not a texture'); } } else { this.states.error.set('bgTexture node not found'); } } else { this.object.environment = null; } } // // // MATERIAL OVERRIDE // // private _update_material_override() { if (this.pv.useOverrideMaterial) { const node = this.p.overrideMaterial.found_node(); if (node) { if (node.nodeContext() == NodeContext.MAT) { (node as BaseMatNodeType).requestContainer().then((container) => { this.object.overrideMaterial = container.material(); }); } else { this.states.error.set('bgTexture node is not a material'); } } else { this.states.error.set('bgTexture node not found'); } } else { this.object.overrideMaterial = null; } } }