three.js 场景编辑器 源码解析(七)

    这一章讲解整个编辑器中最重要的一个文件editor\js\Editor.js,这个文件是真个编辑器的上下文,是所有ui与对象交互的桥梁,相当于mvc模式中的controller。

    Editor.js包含的几个重要的信息如下:

  1. 整个编辑器的相机DEFAULT_CAMERA
  2. 整个编辑器的场景this.scene
  3.  整个场景中辅助相关对象所在的场景this.sceneHelpers
  4. 编辑器中信息传递的介质this.signals
  5. 整个场景的资源信息包括this.object、this.geometries、this.materials、this.textures、this.scripts、this.animations、this.mixer、this.helpers
  6. 编辑器中当前关注的对象this.selected
  7. 编辑器的配置信息(初始化时默认配置)this.config
  8. 编辑器的历史操作信息this.history
  9. 编辑器存储相关信息this.storage
  10. 编辑器的ui文本信息this.strings
  11. 编辑器的文件加载器,主要是导入json、对象等this.loader
    //编辑器的上下文(是各个子类的桥梁,各个子模块通信的桥梁)
    var Editor = function () {
    
    	this.DEFAULT_CAMERA = new THREE.PerspectiveCamera( 50, 1, 0.01, 1000 );
    	this.DEFAULT_CAMERA.name = 'Camera';
    	this.DEFAULT_CAMERA.position.set( 0, 5, 10 );
    	this.DEFAULT_CAMERA.lookAt( new THREE.Vector3() );
    	//信号库
    	var Signal = signals.Signal;
    
    	//各种信号(信号中心,都是通过editor中定义的全局变量来在各个组件中共享的)
    	this.signals = {
    
    		// script
    		// 脚本监听
    		editScript: new Signal(),
    
    		// player
    		// 播放器开始、停止监听
    		startPlayer: new Signal(),
    		stopPlayer: new Signal(),
    
    		// actions
    		//显示模型监听?
    		showModal: new Signal(),
    
    		// notifications
    		//清空编辑器监听?
    		editorCleared: new Signal(),
    
    		//开始保存监听、保存完成监听
    		savingStarted: new Signal(),
    		savingFinished: new Signal(),
    
    		//主题改变监听
    		themeChanged: new Signal(),
    
    		//变换改变监听(平移、旋转、缩放)
    		transformModeChanged: new Signal(),
    		snapChanged: new Signal(),		//选取监听?
    		spaceChanged: new Signal(),		//?
    		rendererChanged: new Signal(),	//?
    
    		//场景背景改变监听、雾监听、场景图改变监听
    		sceneBackgroundChanged: new Signal(),
    		sceneFogChanged: new Signal(),
    		sceneGraphChanged: new Signal(),
    
    		//相机改变监听
    		cameraChanged: new Signal(),
    
    		//几何数据改变监听
    		geometryChanged: new Signal(),
    
    		//选择对象、设置焦点对象监听
    		objectSelected: new Signal(),
    		objectFocused: new Signal(),
    
    
    		//对象的添加、改变、移除监听
    		objectAdded: new Signal(),
    		objectChanged: new Signal(),
    		objectRemoved: new Signal(),
    
    		//添加、移除辅助信息监听
    		helperAdded: new Signal(),
    		helperRemoved: new Signal(),
    
    		//材质改变监听
    		materialChanged: new Signal(),
    
    		//添加、改变、移除脚本监听
    		scriptAdded: new Signal(),
    		scriptChanged: new Signal(),
    		scriptRemoved: new Signal(),
    
    		//窗口改变大小监听
    		windowResize: new Signal(),
    
    		// 网格监听、刷新边栏监听、历史改变监听
    		showGridChanged: new Signal(),
    		refreshSidebarObject3D: new Signal(),
    		historyChanged: new Signal()
    
    	};
    
    	//配置类(配置的信息保存在浏览器的localstring中)
    	this.config = new Config();
    	//历史类
    	this.history = new History( this );
    	//存储类,封装了浏览器数据库的操作
    	this.storage = new Storage();
    	//编辑器ui中的所有文本信息
    	this.strings = new Strings( this.config );
    	//文件加载器,可以加载模型、发布的json文件、压缩文件
    	this.loader = new Loader( this );
    
    	//克隆相机
    	this.camera = this.DEFAULT_CAMERA.clone();
    
    	//创建场景
    	this.scene = new THREE.Scene();
    	this.scene.name = 'Scene';
    	this.scene.background = new THREE.Color( 0xaaaaaa );
    
    	//创建辅助场景展示的模型
    	this.sceneHelpers = new THREE.Scene();
    
    	//场景中所有的对象、几何体、材质、纹理、脚本
    	this.object = {};
    	this.geometries = {};
    	this.materials = {};
    	this.textures = {};
    	this.scripts = {};
    
    	//所有的动画
    	this.animations = {};
    	//创建一个混合器,所有的动画骨骼名称对应的mesh都会在整个场景中查找
    	this.mixer = new THREE.AnimationMixer( this.scene );    
    
    	//选择的对象、所有的辅助的东西
    	this.selected = null;
    	this.helpers = {};
    
    };
    
    Editor.prototype = {
    
    	setTheme: function ( value ) {
    		//设置主题div
    		document.getElementById( 'theme' ).href = value;
    		//派发消息
    		this.signals.themeChanged.dispatch( value );
    
    	},
    
    	//
    	//设置场景
    	setScene: function ( scene ) {
    		//场景名称、id
    		this.scene.uuid = scene.uuid;
    		this.scene.name = scene.name;
    
    		//场景的背景、雾
    		if ( scene.background !== null ) this.scene.background = scene.background.clone();
    		if ( scene.fog !== null ) this.scene.fog = scene.fog.clone();
    
    		//场景的数据
    		this.scene.userData = JSON.parse( JSON.stringify( scene.userData ) );
    
    		// avoid render per object
    		//禁用场景图改变
    		this.signals.sceneGraphChanged.active = false;
    
    		//场景的子节点
    		while ( scene.children.length > 0 ) {
    			//添加子节点
    			this.addObject( scene.children[ 0 ] );
    
    		}
    
    		//启用场景图改变
    		this.signals.sceneGraphChanged.active = true;
    		this.signals.sceneGraphChanged.dispatch();
    
    	},
    
    	//
    	//新建一个对象
    	addObject: function ( object ) {
    		
    		var scope = this;
    		//遍历对象
    		object.traverse( function ( child ) {
    
    			//存储所有的几何数据、材质数据
    			if ( child.geometry !== undefined ) scope.addGeometry( child.geometry );
    			if ( child.material !== undefined ) scope.addMaterial( child.material );
    
    			//添加辅助信息
    			scope.addHelper( child );
    
    		} );
    
    		//对象添加到场景中
    		this.scene.add( object );
    
    		//派发消息
    		this.signals.objectAdded.dispatch( object );
    		this.signals.sceneGraphChanged.dispatch();
    
    	},
    
    	//移动对象(主要是材质场景树,将一个模型变为另一个模型的子节点)
    	moveObject: function ( object, parent, before ) {
    
    		if ( parent === undefined ) {
    
    			parent = this.scene;
    
    		}
    
    		parent.add( object );
    
    		// sort children array
    
    		if ( before !== undefined ) {
    
    			var index = parent.children.indexOf( before );
    			parent.children.splice( index, 0, object );
    			parent.children.pop();
    
    		}
    
    		this.signals.sceneGraphChanged.dispatch();
    
    	},
    
    	//重命名对象
    	nameObject: function ( object, name ) {
    
    		object.name = name;
    		this.signals.sceneGraphChanged.dispatch();
    
    	},
    
    	//删除所有的对象
    	removeObject: function ( object ) {
    		//没有父节点,就返回
    		if ( object.parent === null ) return; // avoid deleting the camera or scene
    		
    		var scope = this;
    
    		//遍历对象、移除所有的辅助
    		object.traverse( function ( child ) {
    
    			scope.removeHelper( child );
    
    		} );
    
    		//移除该对象
    		object.parent.remove( object );
    
    		//对象移除事件、场景图改变事件
    		this.signals.objectRemoved.dispatch( object );
    		this.signals.sceneGraphChanged.dispatch();
    
    	},
    
    	//添加几何数据
    	addGeometry: function ( geometry ) {
    		//所有的几何数据都存储在这里了(几何数据id--几何数据)
    		this.geometries[ geometry.uuid ] = geometry;
    
    	},
    
    	//设置几何数据名称
    	setGeometryName: function ( geometry, name ) {
    
    		geometry.name = name;
    		this.signals.sceneGraphChanged.dispatch();
    
    	},
    
    	//添加材质
    	addMaterial: function ( material ) {
    
    		this.materials[ material.uuid ] = material;
    
    	},
    
    	//修改材质名称
    	setMaterialName: function ( material, name ) {
    
    		material.name = name;
    		this.signals.sceneGraphChanged.dispatch();
    
    	},
    
    	//添加纹理
    	addTexture: function ( texture ) {
    		//场景中所有的纹理都存在这里了(纹理id---纹理)
    		this.textures[ texture.uuid ] = texture;
    
    	},
    
    	//添加动画
    	addAnimation: function ( object, animations ) {
    		//动画
    		if ( animations.length > 0 ) {
    			//场景中所有的动画都存储在这里了(对象id---对象动画)
    			this.animations[ object.uuid ] = animations;
    
    		}
    
    	},
    
    	//
    	//添加辅助信息
    	addHelper: function () {
    		//小圆球作为辅助模型(小球几何数据全局只有一个,选中那个物体就把辅助小球显示在那个物体上)
    		var geometry = new THREE.SphereBufferGeometry( 2, 4, 2 );
    		var material = new THREE.MeshBasicMaterial( { color: 0xff0000, visible: false } );
    		//
    		return function ( object ) {
    
    			var helper;
    
    			if ( object.isCamera ) {  //选中相机
    
    				helper = new THREE.CameraHelper( object, 1 );
    
    			} else if ( object.isPointLight ) {	//选中点光源
    
    				helper = new THREE.PointLightHelper( object, 1 );
    
    			} else if ( object.isDirectionalLight ) {	//选中方向光
    
    				helper = new THREE.DirectionalLightHelper( object, 1 );
    
    			} else if ( object.isSpotLight ) {	//选中聚光灯
    
    				helper = new THREE.SpotLightHelper( object, 1 );
    
    			} else if ( object.isHemisphereLight ) {	//选中半球光
    
    				helper = new THREE.HemisphereLightHelper( object, 1 );
    
    			} else if ( object.isSkinnedMesh ) {	//选中骨骼模型
    
    				helper = new THREE.SkeletonHelper( object );  //添加辅助骨架
    
    			} else {	//其他的对象没有辅助信息
    
    				// no helper for this object type
    				return;
    
    			}
    
    			//创建一个模型对象,将该对象添加到辅助模型上
    			var picker = new THREE.Mesh( geometry, material );
    			picker.name = 'picker';
    			picker.userData.object = object;
    			helper.add( picker );
    
    			//辅助信息添加到辅助场景当中
    			this.sceneHelpers.add( helper );
    			//辅助对象存储
    			this.helpers[ object.id ] = helper;
    			//辅助信息派发
    			this.signals.helperAdded.dispatch( helper );
    
    		};
    
    	}(),
    
    	//移出辅助信息
    	removeHelper: function ( object ) {
    
    		//如果这个对象有辅助信息
    		if ( this.helpers[ object.id ] !== undefined ) {
    			//获取辅助信息,然后删除
    			var helper = this.helpers[ object.id ];
    			helper.parent.remove( helper );
    
    			delete this.helpers[ object.id ];
    			//派发消息
    			this.signals.helperRemoved.dispatch( helper );
    
    		}
    
    	},
    
    	//
    	//添加脚本
    	addScript: function ( object, script ) {
    
    		if ( this.scripts[ object.uuid ] === undefined ) {
    
    			this.scripts[ object.uuid ] = [];
    
    		}
    
    		this.scripts[ object.uuid ].push( script );
    
    		this.signals.scriptAdded.dispatch( script );
    
    	},
    
    	//移出脚本
    	removeScript: function ( object, script ) {
    
    		//没有脚本就返回
    		if ( this.scripts[ object.uuid ] === undefined ) return;
    
    		//查找脚本索引
    		var index = this.scripts[ object.uuid ].indexOf( script );
    
    		//相应的脚本就删除
    		if ( index !== - 1 ) {
    
    			this.scripts[ object.uuid ].splice( index, 1 );
    
    		}
    
    		//派发消息
    		this.signals.scriptRemoved.dispatch( script );
    
    	},
    
    	//获取对象的材质
    	getObjectMaterial: function ( object, slot ) {
    		//获取材质
    		var material = object.material;
    		//是否材质数组
    		if ( Array.isArray( material ) ) {
    			//按照材质索引获取材质
    			material = material[ slot ];
    
    		}
    
    		return material;
    
    	},
    
    	//对象赋予新的材质,对象可能有多个材质,可以对每一个材质单独设置
    	setObjectMaterial: function ( object, slot, newMaterial ) {
    		//材质数组
    		if ( Array.isArray( object.material ) ) {
    
    			object.material[ slot ] = newMaterial;
    
    		} else {
    			//唯一材质
    			object.material = newMaterial;
    
    		}
    
    	},
    
    	//
    	//选择对象时调用
    	select: function ( object ) {
    		//如果选择的对象是自己就返回
    		if ( this.selected === object ) return;
    		//
    		var uuid = null;
    		//对象存在就设置uuid
    		if ( object !== null ) {
    
    			uuid = object.uuid;
    
    		}
    		//设置为选择的对象
    		this.selected = object;
    		//config应该是一个配置文件,可能是关联了localstring
    		this.config.setKey( 'selected', uuid );
    		//派发对象选中的信息
    		this.signals.objectSelected.dispatch( object );
    
    	},
    
    	//通过id选择对象
    	selectById: function ( id ) {
    
    		//如果选择的是相机
    		if ( id === this.camera.id ) {
    
    			this.select( this.camera );
    			return;
    
    		}
    
    		this.select( this.scene.getObjectById( id, true ) );
    
    	},
    
    	//通过id选择对象
    	selectByUuid: function ( uuid ) {
    
    		var scope = this;
    
    		this.scene.traverse( function ( child ) {
    
    			if ( child.uuid === uuid ) {
    
    				scope.select( child );
    
    			}
    
    		} );
    
    	},
    
    	//撤销选择对象
    	deselect: function () {
    
    		this.select( null );
    
    	},
    
    	//聚焦对象
    	focus: function ( object ) {
    
    		this.signals.objectFocused.dispatch( object );
    
    	},
    
    	//通过id聚焦对象
    	focusById: function ( id ) {
    
    		this.focus( this.scene.getObjectById( id, true ) );
    
    	},
    
    	clear: function () {
    		//清除历史、清除存储
    		this.history.clear();
    		this.storage.clear();
    		//相机默认、北京默认、雾默认
    		this.camera.copy( this.DEFAULT_CAMERA );
    		this.scene.background.setHex( 0xaaaaaa );
    		this.scene.fog = null;
    		//场景中的对象
    		var objects = this.scene.children;
    		//遍历场景中的对象
    		while ( objects.length > 0 ) {
    			//删除对象
    			this.removeObject( objects[ 0 ] );
    
    		}
    
    		//几何数据、材质数据、纹理数据、脚本数据都删除
    		this.geometries = {};
    		this.materials = {};
    		this.textures = {};
    		this.scripts = {};
    		//动画置空,停止所有的动画
    		this.animations = {};
    		this.mixer.stopAllAction();
    		//选择置空
    		this.deselect();
    		//清除所有的编辑项
    		this.signals.editorCleared.dispatch();
    
    	},
    
    	//
    	//反序列化
    	fromJSON: function ( json ) {
    		//创建对象解析器
    		var loader = new THREE.ObjectLoader();
    
    		// backwards
    		// 场景未定义,创建一个场景,然后返回
    		if ( json.scene === undefined ) {
    			//
    			this.setScene( loader.parse( json ) );
    			return;
    
    		}
    
    		//解析相机
    		var camera = loader.parse( json.camera );
    
    		//设置相机参数
    		this.camera.copy( camera );
    		this.camera.aspect = this.DEFAULT_CAMERA.aspect;
    		this.camera.updateProjectionMatrix();
    
    		//解析历史、脚本
    		this.history.fromJSON( json.history );
    		this.scripts = json.scripts;
    
    		//解析场景
    		this.setScene( loader.parse( json.scene ) );
    
    	},
    
    	toJSON: function () {
    
    		// scripts clean up
    		//获取场景、脚本
    		var scene = this.scene;
    		var scripts = this.scripts;
    
    		//遍历场景中所有脚本的key-value(对象名称--脚本)
    		for ( var key in scripts ) {
    			//获取一个对象的所有脚本
    			var script = scripts[ key ];
    			//如果没有这个脚本就删除
    			if ( script.length === 0 || scene.getObjectByProperty( 'uuid', key ) === undefined ) {
    
    				delete scripts[ key ];
    
    			}
    
    		}
    
    		//
    
    		return {
    			
    			metadata: {},													//元数据
    			project: {
    				shadows: this.config.getKey( 'project/renderer/shadows' ),	//工程的阴影设置
    				vr: this.config.getKey( 'project/vr' )						//是否vr
    			},
    			camera: this.camera.toJSON(),									//相机的信息
    			scene: this.scene.toJSON(),										//场景的信息
    			scripts: this.scripts,											//脚本的信息
    			history: this.history.toJSON()									//历史信息
    
    		};
    
    	},
    
    	objectByUuid: function ( uuid ) {
    		//根据uuid获取一个对象
    		return this.scene.getObjectByProperty( 'uuid', uuid, true );
    
    	},
    
    	//执行命令
    	execute: function ( cmd, optionalName ) {
    
    		//首先添加到执行列表中,等待执行
    		this.history.execute( cmd, optionalName );
    
    	},
    
    	undo: function () {
    		//撤销上一个命令
    		this.history.undo();
    
    	},
    
    	redo: function () {
    		//重做上一个命令
    		this.history.redo();
    
    	}
    
    };
    

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值